home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / usenet / sources / volume89 / unix / rcs.02 < prev    next >
Internet Message Format  |  1989-11-19  |  93KB

  1. Path: xanth!ames!sun-barr!newstop!sun!swap!page
  2. From: page%swap@Sun.COM (Bob Page)
  3. Newsgroups: comp.sources.amiga
  4. Subject: v89i217:  rcs - revision control system, Part02/14
  5. Message-ID: <128093@sun.Eng.Sun.COM>
  6. Date: 19 Nov 89 09:24:20 GMT
  7. Sender: news@sun.Eng.Sun.COM
  8. Lines: 3240
  9. Approved: page@sun.com
  10.  
  11. Submitted-by: rsbx@cbmvax.commodore.com (Raymond S. Brand)
  12. Posting-number: Volume 89, Issue 217
  13. Archive-name: unix/rcs.02
  14.  
  15. # This is a shell archive.
  16. # Remove anything above and including the cut line.
  17. # Then run the rest of the file through 'sh'.
  18. # Unpacked files will be owned by you and have default permissions.
  19. #----cut here-----cut here-----cut here-----cut here----#
  20. #!/bin/sh
  21. # shar: SHell ARchive
  22. # Run the following text through 'sh' to create:
  23. #    diff/analyze.c
  24. #    diff/context.c
  25. #    diff/diff.c
  26. #    diff/diff3.c
  27. # This is archive 2 of a 14-part kit.
  28. # This archive created: Sun Nov 19 01:12:04 1989
  29. if `test ! -d diff`
  30. then
  31.   mkdir diff
  32.   echo "mkdir diff"
  33. fi
  34. echo "extracting diff/analyze.c"
  35. sed 's/^X//' << \SHAR_EOF > diff/analyze.c
  36. X/* Analyze file differences for GNU DIFF.
  37. X   Copyright (C) 1988, 1989 Free Software Foundation, Inc.
  38. X
  39. XThis file is part of GNU DIFF.
  40. X
  41. XGNU DIFF is free software; you can redistribute it and/or modify
  42. Xit under the terms of the GNU General Public License as published by
  43. Xthe Free Software Foundation; either version 1, or (at your option)
  44. Xany later version.
  45. X
  46. XGNU DIFF is distributed in the hope that it will be useful,
  47. Xbut WITHOUT ANY WARRANTY; without even the implied warranty of
  48. XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  49. XGNU General Public License for more details.
  50. X
  51. XYou should have received a copy of the GNU General Public License
  52. Xalong with GNU DIFF; see the file COPYING.  If not, write to
  53. Xthe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  54. X
  55. X/* The basic algorithm is described in: 
  56. X   "An O(ND) Difference Algorithm and its Variations", Eugene Myers,
  57. X   Algorithmica Vol. 1 No. 2, 1986, p 251.  */
  58. X
  59. X#include "regex.h"
  60. X#include "diff.h"
  61. X
  62. Xextern int no_discards;
  63. X
  64. Xstatic int *xvec, *yvec;    /* Vectors being compared. */
  65. Xstatic int *fdiag;        /* Vector, indexed by diagonal, containing
  66. X                   the X coordinate of the point furthest
  67. X                   along the given diagonal in the forward
  68. X                   search of the edit matrix. */
  69. Xstatic int *bdiag;        /* Vector, indexed by diagonal, containing
  70. X                   the X coordinate of the point furthest
  71. X                   along the given diagonal in the backward
  72. X                   search of the edit matrix. */
  73. X
  74. X/* Find the midpoint of the shortest edit script for a specified
  75. X   portion of the two files.
  76. X
  77. X   We scan from the beginnings of the files, and simultaneously from the ends,
  78. X   doing a breadth-first search through the space of edit-sequence.
  79. X   When the two searches meet, we have found the midpoint of the shortest
  80. X   edit sequence.
  81. X
  82. X   The value returned is the number of the diagonal on which the midpoint lies.
  83. X   The diagonal number equals the number of inserted lines minus the number
  84. X   of deleted lines (counting only lines before the midpoint).
  85. X   The edit cost is stored into *COST; this is the total number of
  86. X   lines inserted or deleted (counting only lines before the midpoint).
  87. X
  88. X   This function assumes that the first lines of the specified portions
  89. X   of the two files do not match, and likewise that the last lines do not
  90. X   match.  The caller must trim matching lines from the beginning and end
  91. X   of the portions it is going to specify.
  92. X
  93. X   Note that if we return the "wrong" diagonal value, or if
  94. X   the value of bdiag at that diagonal is "wrong",
  95. X   the worst this can do is cause suboptimal diff output.
  96. X   It cannot cause incorrect diff output.  */
  97. X
  98. Xstatic int
  99. Xdiag (xoff, xlim, yoff, ylim, cost)
  100. X     int xoff, xlim, yoff, ylim;
  101. X     int *cost;
  102. X{
  103. X  int *const fd = fdiag;    /* Give the compiler a chance. */
  104. X  int *const bd = bdiag;    /* Additional help for the compiler. */
  105. X  int *const xv = xvec;        /* Still more help for the comiler. */
  106. X  int *const yv = yvec;        /* And more and more . . . */
  107. X  const int dmin = xoff - ylim;    /* Minimum valid diagonal. */
  108. X  const int dmax = xlim - yoff;    /* Maximum valid diagonal. */
  109. X  const int fmid = xoff - yoff;    /* Center diagonal of top-down search. */
  110. X  const int bmid = xlim - ylim;    /* Center diagonal of bottom-up search. */
  111. X  int fmin = fmid, fmax = fmid;    /* Limits of top-down search. */
  112. X  int bmin = bmid, bmax = bmid;    /* Limits of bottom-up search. */
  113. X  int c;            /* Cost. */
  114. X  int odd = fmid - bmid & 1;    /* True if southeast corner is on an odd
  115. X                   diagonal with respect to the northwest. */
  116. X
  117. X  fd[fmid] = xoff;
  118. X  bd[bmid] = xlim;
  119. X
  120. X  for (c = 1;; ++c)
  121. X    {
  122. X      int d;            /* Active diagonal. */
  123. X      int big_snake = 0;
  124. X
  125. X      /* Extend the top-down search by an edit step in each diagonal. */
  126. X      fmin > dmin ? fd[--fmin - 1] = -1 : ++fmin;
  127. X      fmax < dmax ? fd[++fmax + 1] = -1 : --fmax;
  128. X      for (d = fmax; d >= fmin; d -= 2)
  129. X    {
  130. X      int x, y, oldx, tlo = fd[d - 1], thi = fd[d + 1];
  131. X
  132. X      if (tlo >= thi)
  133. X        x = tlo + 1;
  134. X      else
  135. X        x = thi;
  136. X      oldx = x;
  137. X      y = x - d;
  138. X      while (x < xlim && y < ylim && xv[x] == yv[y])
  139. X        ++x, ++y;
  140. X      if (x - oldx > 20)
  141. X        big_snake = 1;
  142. X      fd[d] = x;
  143. X      if (odd && bmin <= d && d <= bmax && bd[d] <= fd[d])
  144. X        {
  145. X          *cost = 2 * c - 1;
  146. X          return d;
  147. X        }
  148. X    }
  149. X
  150. X      /* Similar extend the bottom-up search. */
  151. X      bmin > dmin ? bd[--bmin - 1] = INT_MAX : ++bmin;
  152. X      bmax < dmax ? bd[++bmax + 1] = INT_MAX : --bmax;
  153. X      for (d = bmax; d >= bmin; d -= 2)
  154. X    {
  155. X      int x, y, oldx, tlo = bd[d - 1], thi = bd[d + 1];
  156. X
  157. X      if (tlo < thi)
  158. X        x = tlo;
  159. X      else
  160. X        x = thi - 1;
  161. X      oldx = x;
  162. X      y = x - d;
  163. X      while (x > xoff && y > yoff && xv[x - 1] == yv[y - 1])
  164. X        --x, --y;
  165. X      if (oldx - x > 20)
  166. X        big_snake = 1;
  167. X      bd[d] = x;
  168. X      if (!odd && fmin <= d && d <= fmax && bd[d] <= fd[d])
  169. X        {
  170. X          *cost = 2 * c;
  171. X          return d;
  172. X        }
  173. X    }
  174. X
  175. X      /* Heuristic: check occasionally for a diagonal that has made
  176. X     lots of progress compared with the edit distance.
  177. X     If we have any such, find the one that has made the most
  178. X     progress and return it as if it had succeeded.
  179. X
  180. X     With this heuristic, for files with a constant small density
  181. X     of changes, the algorithm is linear in the file size.  */
  182. X
  183. X      if (c > 200 && big_snake && heuristic)
  184. X    {
  185. X      int best;
  186. X      int bestpos;
  187. X
  188. X      best = 0;
  189. X      for (d = fmax; d >= fmin; d -= 2)
  190. X        {
  191. X          int dd = d - fmid;
  192. X          if ((fd[d] - xoff)*2 - dd > 12 * (c + (dd > 0 ? dd : -dd)))
  193. X        {
  194. X          if (fd[d] * 2 - dd > best
  195. X              && fd[d] - xoff > 20
  196. X              && fd[d] - d - yoff > 20)
  197. X            {
  198. X              int k;
  199. X              int x = fd[d];
  200. X
  201. X              /* We have a good enough best diagonal;
  202. X             now insist that it end with a significant snake.  */
  203. X              for (k = 1; k <= 20; k++)
  204. X            if (xvec[x - k] != yvec[x - d - k])
  205. X              break;
  206. X
  207. X              if (k == 21)
  208. X            {
  209. X              best = fd[d] * 2 - dd;
  210. X              bestpos = d;
  211. X            }
  212. X            }
  213. X        }
  214. X        }
  215. X      if (best > 0)
  216. X        {
  217. X          *cost = 2 * c - 1;
  218. X          return bestpos;
  219. X        }
  220. X
  221. X      best = 0;
  222. X      for (d = bmax; d >= bmin; d -= 2)
  223. X        {
  224. X          int dd = d - bmid;
  225. X          if ((xlim - bd[d])*2 + dd > 12 * (c + (dd > 0 ? dd : -dd)))
  226. X        {
  227. X          if ((xlim - bd[d]) * 2 + dd > best
  228. X              && xlim - bd[d] > 20
  229. X              && ylim - (bd[d] - d) > 20)
  230. X            {
  231. X              /* We have a good enough best diagonal;
  232. X             now insist that it end with a significant snake.  */
  233. X              int k;
  234. X              int x = bd[d];
  235. X
  236. X              for (k = 0; k < 20; k++)
  237. X            if (xvec[x + k] != yvec[x - d + k])
  238. X              break;
  239. X              if (k == 20)
  240. X            {
  241. X              best = (xlim - bd[d]) * 2 + dd;
  242. X              bestpos = d;
  243. X            }
  244. X            }
  245. X        }
  246. X        }
  247. X      if (best > 0)
  248. X        {
  249. X          *cost = 2 * c - 1;
  250. X          return bestpos;
  251. X        }
  252. X    }
  253. X    }
  254. X}
  255. X
  256. X/* Compare in detail contiguous subsequences of the two files
  257. X   which are known, as a whole, to match each other.
  258. X
  259. X   The results are recorded in the vectors files[N].changed_flag, by
  260. X   storing a 1 in the element for each line that is an insertion or deletion.
  261. X
  262. X   The subsequence of file 0 is [XOFF, XLIM) and likewise for file 1.
  263. X
  264. X   Note that XLIM, YLIM are exclusive bounds.
  265. X   All line numbers are origin-0 and discarded lines are not counted.  */
  266. X
  267. Xstatic void
  268. Xcompareseq (xoff, xlim, yoff, ylim)
  269. X     int xoff, xlim, yoff, ylim;
  270. X{
  271. X  /* Slide down the bottom initial diagonal. */
  272. X  while (xoff < xlim && yoff < ylim && xvec[xoff] == yvec[yoff])
  273. X    ++xoff, ++yoff;
  274. X  /* Slide up the top initial diagonal. */
  275. X  while (xlim > xoff && ylim > yoff && xvec[xlim - 1] == yvec[ylim - 1])
  276. X    --xlim, --ylim;
  277. X  
  278. X  /* Handle simple cases. */
  279. X  if (xoff == xlim)
  280. X    while (yoff < ylim)
  281. X      files[1].changed_flag[files[1].realindexes[yoff++]] = 1;
  282. X  else if (yoff == ylim)
  283. X    while (xoff < xlim)
  284. X      files[0].changed_flag[files[0].realindexes[xoff++]] = 1;
  285. X  else
  286. X    {
  287. X      int c, d, f, b;
  288. X
  289. X      /* Find a point of correspondence in the middle of the files.  */
  290. X
  291. X      d = diag (xoff, xlim, yoff, ylim, &c);
  292. X      f = fdiag[d];
  293. X      b = bdiag[d];
  294. X
  295. X      if (c == 1)
  296. X    {
  297. X      /* This should be impossible, because it implies that
  298. X         one of the two subsequences is empty,
  299. X         and that case was handled above without calling `diag'.
  300. X         Let's verify that this is true.  */
  301. X      abort ();
  302. X#if 0
  303. X      /* The two subsequences differ by a single insert or delete;
  304. X         record it and we are done.  */
  305. X      if (d < xoff - yoff)
  306. X        files[1].changed_flag[files[1].realindexes[b - d - 1]] = 1;
  307. X      else
  308. X        files[0].changed_flag[files[0].realindexes[b]] = 1;
  309. X#endif
  310. X    }
  311. X      else
  312. X    {
  313. X      /* Use that point to split this problem into two subproblems.  */
  314. X      compareseq (xoff, b, yoff, b - d);
  315. X      /* This used to use f instead of b,
  316. X         but that is incorrect!
  317. X         It is not necessarily the case that diagonal d
  318. X         has a snake from b to f.  */
  319. X      compareseq (b, xlim, b - d, ylim);
  320. X    }
  321. X    }
  322. X}
  323. X
  324. X/* Discard lines from one file that have no matches in the other file.
  325. X
  326. X   A line which is discarded will not be considered by the actual
  327. X   comparison algorithm; it will be as if that line were not in the file.
  328. X   The file's `realindexes' table maps virtual line numbers
  329. X   (which don't count the discarded lines) into real line numbers;
  330. X   this is how the actual comparison algorithm produces results
  331. X   that are comprehensible when the discarded lines are counted.
  332. X
  333. X   When we discard a line, we also mark it as a deletion or insertion
  334. X   so that it will be printed in the output.  */
  335. X
  336. Xvoid
  337. Xdiscard_confusing_lines (filevec)
  338. X     struct file_data filevec[];
  339. X{
  340. X  int f, i, j;
  341. X  char *discarded[2];
  342. X  int *equiv_count[2];
  343. X
  344. X  /* Allocate our results.  */
  345. X  for (f = 0; f < 2; f++)
  346. X    {
  347. X      filevec[f].undiscarded
  348. X    = (int *) xmalloc (filevec[f].buffered_lines * sizeof (int));
  349. X      filevec[f].realindexes
  350. X    = (int *) xmalloc (filevec[f].buffered_lines * sizeof (int));
  351. X    }
  352. X
  353. X  /* Set up equiv_count[F][I] as the number of lines in file F
  354. X     that fall in equivalence class I.  */
  355. X
  356. X  equiv_count[0] = (int *) xmalloc (filevec[0].equiv_max * sizeof (int));
  357. X  bzero (equiv_count[0], filevec[0].equiv_max * sizeof (int));
  358. X  equiv_count[1] = (int *) xmalloc (filevec[1].equiv_max * sizeof (int));
  359. X  bzero (equiv_count[1], filevec[1].equiv_max * sizeof (int));
  360. X
  361. X  for (i = 0; i < filevec[0].buffered_lines; ++i)
  362. X    ++equiv_count[0][filevec[0].equivs[i]];
  363. X  for (i = 0; i < filevec[1].buffered_lines; ++i)
  364. X    ++equiv_count[1][filevec[1].equivs[i]];
  365. X
  366. X  /* Set up tables of which lines are going to be discarded.  */
  367. X
  368. X  discarded[0] = (char *) xmalloc (filevec[0].buffered_lines);
  369. X  discarded[1] = (char *) xmalloc (filevec[1].buffered_lines);
  370. X  bzero (discarded[0], filevec[0].buffered_lines);
  371. X  bzero (discarded[1], filevec[1].buffered_lines);
  372. X
  373. X  /* Mark to be discarded each line that matches no line of the other file.
  374. X     If a line matches many lines, mark it as provisionally discardable.  */
  375. X
  376. X  for (f = 0; f < 2; f++)
  377. X    {
  378. X      int end = filevec[f].buffered_lines;
  379. X      char *discards = discarded[f];
  380. X      int *counts = equiv_count[1 - f];
  381. X      int *equivs = filevec[f].equivs;
  382. X      for (i = 0; i < end; i++)
  383. X    {
  384. X      int nmatch = counts[equivs[i]];
  385. X      if (equivs[i] == 0)
  386. X        continue;
  387. X      if (nmatch == 0)
  388. X        discards[i] = 1;
  389. X      else if (nmatch > 5)
  390. X        discards[i] = 2;
  391. X    }
  392. X    }
  393. X
  394. X  /* Don't really discard the provisional lines if there are less than ten
  395. X     discardable lines in a row.  */
  396. X
  397. X  for (f = 0; f < 2; f++)
  398. X    {
  399. X      int end = filevec[f].buffered_lines;
  400. X      char *discards = discarded[f];
  401. X
  402. X      for (i = 0; i < end; i++)
  403. X    if (discards[i])
  404. X      {
  405. X        register int j;
  406. X        int length;
  407. X        int provisional = 0;
  408. X
  409. X        /* Cancel provisional discards at the beginning.  */
  410. X        while (i < end && discards[i] == 2)
  411. X          discards[i] = 0;
  412. X
  413. X        /* Find end of this run of discardable lines.
  414. X           Count how many are provisionally discardable.  */
  415. X        for (j = i; j < end; j++)
  416. X          {
  417. X        if (discards[j] == 0)
  418. X          break;
  419. X        if (discards[j] == 2)
  420. X          ++provisional;
  421. X          }
  422. X
  423. X        /* Cancel provisional discards at the end, and shrink the run.  */
  424. X        while (j > i && discards[j - 1] == 2)
  425. X          discards[j - 1] = 0, --provisional;
  426. X
  427. X        /* Now we have the length of a run of discardable lines
  428. X           whose first and last are not provisional.  */
  429. X        length = j - i;
  430. X
  431. X        /* If half the lines in the run are provisional,
  432. X           cancel discarding of all provisional lines in the run.  */
  433. X        if (provisional * 2 > length)
  434. X          {
  435. X        while (j > i)
  436. X          if (discards[--j] == 2)
  437. X            discards[j] = 0;
  438. X          }
  439. X        else
  440. X          {
  441. X        /* Cancel provisional discards that are near either end.  */
  442. X        for (j = 0; j < 5 && j < length; j++)
  443. X          if (discards[i + j] == 2)
  444. X            discards[i + j] = 0;
  445. X        /* Meanwhile, I advances to the last line of the run.  */
  446. X        i += length - 1;
  447. X        length -= 5;
  448. X        for (j = 0; j < 5 && j < length; j++)
  449. X          if (discards[i - j] == 2)
  450. X            discards[i - j] = 0;
  451. X          }
  452. X      }
  453. X    }
  454. X
  455. X  /* Discard from file 0. */
  456. X  for (f = 0; f < 2; f++)
  457. X    {
  458. X      char *discards = discarded[f];
  459. X      int end = filevec[f].buffered_lines;
  460. X      j = 0;
  461. X      for (i = 0; i < end; ++i)
  462. X    if (no_discards || discards[i] == 0)
  463. X      {
  464. X        filevec[f].undiscarded[j] = filevec[f].equivs[i];
  465. X        filevec[f].realindexes[j++] = i;
  466. X      }
  467. X    else
  468. X      filevec[f].changed_flag[i] = 1;
  469. X      filevec[f].nondiscarded_lines = j;
  470. X    }
  471. X
  472. X  free (discarded[1]);
  473. X  free (discarded[0]);
  474. X  free (equiv_count[1]);
  475. X  free (equiv_count[0]);
  476. X}
  477. X
  478. X/* Adjust inserts/deletes of blank lines to join changes
  479. X   as much as possible.
  480. X
  481. X   We do something when a run of changed lines include a blank
  482. X   line at one end and have an excluded blank line at the other.
  483. X   We are free to choose which blank line is included.
  484. X   `compareseq' always chooses the one at the beginning,
  485. X   but usually it is cleaner to consider the following blank line
  486. X   to be the "change".  The only exception is if the preceding blank line
  487. X   would join this change to other changes.  */
  488. X
  489. Xint inhibit;
  490. X
  491. Xstatic void
  492. Xshift_boundaries (filevec)
  493. X     struct file_data filevec[];
  494. X{
  495. X  int f;
  496. X
  497. X  if (inhibit)
  498. X    return;
  499. X
  500. X  for (f = 0; f < 2; f++)
  501. X    {
  502. X      char *changed = filevec[f].changed_flag;
  503. X      char *other_changed = filevec[1-f].changed_flag;
  504. X      int i = 0;
  505. X      int j = 0;
  506. X      int i_end = filevec[f].buffered_lines;
  507. X      int preceeding = -1;
  508. X      int other_preceeding = -1;
  509. X
  510. X      while (1)
  511. X    {
  512. X      int start, end, other_start;
  513. X
  514. X      /* Scan forwards to find beginning of another run of changes.
  515. X         Also keep track of the corresponding point in the other file.  */
  516. X
  517. X      while (i < i_end && changed[i] == 0)
  518. X        {
  519. X          while (other_changed[j++])
  520. X        /* Non-corresponding lines in the other file
  521. X           will count as the preceeding batch of changes.  */
  522. X        other_preceeding = j;
  523. X          i++;
  524. X        }
  525. X
  526. X      if (i == i_end)
  527. X        break;
  528. X
  529. X      start = i;
  530. X      other_start = j;
  531. X
  532. X      while (1)
  533. X        {
  534. X          /* Now find the end of this run of changes.  */
  535. X
  536. X          while (i < i_end && changed[i] != 0) i++;
  537. X          end = i;
  538. X
  539. X          /* If the first changed line matches the following unchanged one,
  540. X         and this run does not follow right after a previous run,
  541. X         and there are no lines deleted from the other file here,
  542. X         then classify the first changed line as unchanged
  543. X         and the following line as changed in its place.  */
  544. X
  545. X          /* You might ask, how could this run follow right after another?
  546. X         Only because the previous run was shifted here.  */
  547. X
  548. X          if (files[f].equivs[start] == files[f].equivs[end]
  549. X          && !other_changed[j]
  550. X          && end != i_end
  551. X          && !((preceeding >= 0 && start == preceeding)
  552. X               || (other_preceeding >= 0
  553. X               && other_start == other_preceeding)))
  554. X        {
  555. X          changed[end++] = 1;
  556. X          changed[start++] = 0;
  557. X          ++i;
  558. X          /* Since one line-that-matches is now before this run
  559. X             instead of after, we must advance in the other file
  560. X             to keep in synch.  */
  561. X          ++j;
  562. X        }
  563. X          else
  564. X        break;
  565. X        }
  566. X
  567. X      preceeding = i;
  568. X      other_preceeding = j;
  569. X    }
  570. X    }
  571. X}
  572. X
  573. X/* Cons an additional entry onto the front of an edit script OLD.
  574. X   LINE0 and LINE1 are the first affected lines in the two files (origin 0).
  575. X   DELETED is the number of lines deleted here from file 0.
  576. X   INSERTED is the number of lines inserted here in file 1.
  577. X
  578. X   If DELETED is 0 then LINE0 is the number of the line before
  579. X   which the insertion was done; vice versa for INSERTED and LINE1.  */
  580. X
  581. Xstatic struct change *
  582. Xadd_change (line0, line1, deleted, inserted, old)
  583. X     int line0, line1, deleted, inserted;
  584. X     struct change *old;
  585. X{
  586. X  struct change *new = (struct change *) xmalloc (sizeof (struct change));
  587. X
  588. X  new->line0 = line0;
  589. X  new->line1 = line1;
  590. X  new->inserted = inserted;
  591. X  new->deleted = deleted;
  592. X  new->link = old;
  593. X  return new;
  594. X}
  595. X
  596. X/* Scan the tables of which lines are inserted and deleted,
  597. X   producing an edit script in reverse order.  */
  598. X
  599. Xstatic struct change *
  600. Xbuild_reverse_script (filevec)
  601. X     struct file_data filevec[];
  602. X{
  603. X  struct change *script = 0;
  604. X  char *changed0 = filevec[0].changed_flag;
  605. X  char *changed1 = filevec[1].changed_flag;
  606. X  int len0 = filevec[0].buffered_lines;
  607. X  int len1 = filevec[1].buffered_lines;
  608. X
  609. X  /* Note that changedN[len0] does exist, and contains 0.  */
  610. X
  611. X  int i0 = 0, i1 = 0;
  612. X
  613. X  while (i0 < len0 || i1 < len1)
  614. X    {
  615. X      if (changed0[i0] || changed1[i1])
  616. X    {
  617. X      int line0 = i0, line1 = i1;
  618. X
  619. X      /* Find # lines changed here in each file.  */
  620. X      while (changed0[i0]) ++i0;
  621. X      while (changed1[i1]) ++i1;
  622. X
  623. X      /* Record this change.  */
  624. X      script = add_change (line0, line1, i0 - line0, i1 - line1, script);
  625. X    }
  626. X
  627. X      /* We have reached lines in the two files that match each other.  */
  628. X      i0++, i1++;
  629. X    }
  630. X
  631. X  return script;
  632. X}
  633. X
  634. X/* Scan the tables of which lines are inserted and deleted,
  635. X   producing an edit script in forward order.  */
  636. X
  637. Xstatic struct change *
  638. Xbuild_script (filevec)
  639. X     struct file_data filevec[];
  640. X{
  641. X  struct change *script = 0;
  642. X  char *changed0 = filevec[0].changed_flag;
  643. X  char *changed1 = filevec[1].changed_flag;
  644. X  int len0 = filevec[0].buffered_lines;
  645. X  int len1 = filevec[1].buffered_lines;
  646. X
  647. X  /* Note that changedN[-1] does exist, and contains 0.  */
  648. X
  649. X  int i0 = len0, i1 = len1;
  650. X
  651. X  while (i0 >= 0 || i1 >= 0)
  652. X    {
  653. X      if (changed0[i0 - 1] || changed1[i1 - 1])
  654. X    {
  655. X      int line0 = i0, line1 = i1;
  656. X
  657. X      /* Find # lines changed here in each file.  */
  658. X      while (changed0[i0 - 1]) --i0;
  659. X      while (changed1[i1 - 1]) --i1;
  660. X
  661. X      /* Record this change.  */
  662. X      script = add_change (i0, i1, line0 - i0, line1 - i1, script);
  663. X    }
  664. X
  665. X      /* We have reached lines in the two files that match each other.  */
  666. X      i0--, i1--;
  667. X    }
  668. X
  669. X  return script;
  670. X}
  671. X
  672. X/* Report the differences of two files.  DEPTH is the current directory
  673. X   depth. */
  674. Xint
  675. Xdiff_2_files (filevec, depth)
  676. X     struct file_data filevec[];
  677. X     int depth;
  678. X{
  679. X  int diags;
  680. X  int i;
  681. X  struct change *e, *p;
  682. X  struct change *script;
  683. X  int binary;
  684. X
  685. X  /* See if the two named files are actually the same physical file.
  686. X     If so, we know they are identical without actually reading them.  */
  687. X
  688. X#ifndef AMIGA
  689. X  if (filevec[0].stat.st_ino == filevec[1].stat.st_ino
  690. X      && filevec[0].stat.st_dev == filevec[1].stat.st_dev)
  691. X    return 0;
  692. X#endif
  693. X
  694. X  binary = read_files (filevec);
  695. X
  696. X  /* If we have detected that file 0 is a binary file,
  697. X     compare the two files as binary.  This can happen
  698. X     only when the first chunk is read.  */
  699. X
  700. X  if (binary)
  701. X    {
  702. X      int differs = (filevec[0].buffered_chars != filevec[1].buffered_chars
  703. X             || bcmp (filevec[0].buffer, filevec[1].buffer,
  704. X                  filevec[1].buffered_chars));
  705. X      if (differs) 
  706. X    message ("Binary files %s and %s differ\n",
  707. X         filevec[0].name, filevec[1].name);
  708. X
  709. X      for (i = 0; i < 2; ++i)
  710. X    if (filevec[i].buffer)
  711. X      free (filevec[i].buffer);
  712. X      return differs;
  713. X    }
  714. X
  715. X  if (filevec[0].missing_newline != filevec[1].missing_newline)
  716. X    {
  717. X      if (filevec[0].missing_newline)
  718. X    error ("No newline at end of file %s\n", filevec[0].name);
  719. X      if (filevec[1].missing_newline)
  720. X    error ("No newline at end of file %s\n", filevec[1].name);
  721. X    }
  722. X
  723. X  /* Allocate vectors for the results of comparison:
  724. X     a flag for each line of each file, saying whether that line
  725. X     is an insertion or deletion.
  726. X     Allocate an extra element, always zero, at each end of each vector.  */
  727. X
  728. X  filevec[0].changed_flag = (char *) xmalloc (filevec[0].buffered_lines + 2);
  729. X  filevec[1].changed_flag = (char *) xmalloc (filevec[1].buffered_lines + 2);
  730. X  bzero (filevec[0].changed_flag, filevec[0].buffered_lines + 2);
  731. X  bzero (filevec[1].changed_flag, filevec[1].buffered_lines + 2);
  732. X  filevec[0].changed_flag++;
  733. X  filevec[1].changed_flag++;
  734. X
  735. X  /* Some lines are obviously insertions or deletions
  736. X     because they don't match anything.  Detect them now,
  737. X     and avoid even thinking about them in the main comparison algorithm.  */
  738. X
  739. X  discard_confusing_lines (filevec);
  740. X
  741. X  /* Now do the main comparison algorithm, considering just the
  742. X     undiscarded lines.  */
  743. X
  744. X  xvec = filevec[0].undiscarded;
  745. X  yvec = filevec[1].undiscarded;
  746. X  diags = filevec[0].nondiscarded_lines + filevec[1].nondiscarded_lines + 3;
  747. X  fdiag = (int *) xmalloc (diags * sizeof (int));
  748. X  fdiag += filevec[1].nondiscarded_lines + 1;
  749. X  bdiag = (int *) xmalloc (diags * sizeof (int));
  750. X  bdiag += filevec[1].nondiscarded_lines + 1;
  751. X
  752. X  files[0] = filevec[0];
  753. X  files[1] = filevec[1];
  754. X
  755. X  compareseq (0, filevec[0].nondiscarded_lines,
  756. X          0, filevec[1].nondiscarded_lines);
  757. X
  758. X  bdiag -= filevec[1].nondiscarded_lines + 1;
  759. X  free (bdiag);
  760. X  fdiag -= filevec[1].nondiscarded_lines + 1;
  761. X  free (fdiag);
  762. X
  763. X  /* Modify the results slightly to make them prettier
  764. X     in cases where that can validly be done.  */
  765. X
  766. X  shift_boundaries (filevec);
  767. X
  768. X  /* Get the results of comparison in the form of a chain
  769. X     of `struct change's -- an edit script.  */
  770. X
  771. X  if (output_style == OUTPUT_ED)
  772. X    script = build_reverse_script (filevec);
  773. X  else
  774. X    script = build_script (filevec);
  775. X
  776. X  if (script)
  777. X    {
  778. X      setup_output (files[0].name, files[1].name, depth);
  779. X      if (output_style == OUTPUT_CONTEXT)
  780. X    print_context_header (files);
  781. X
  782. X      switch (output_style)
  783. X    {
  784. X    case OUTPUT_CONTEXT:
  785. X      print_context_script (script);
  786. X      break;
  787. X
  788. X    case OUTPUT_ED:
  789. X      print_ed_script (script);
  790. X      break;
  791. X
  792. X    case OUTPUT_FORWARD_ED:
  793. X      pr_forward_ed_script (script);
  794. X      break;
  795. X
  796. X    case OUTPUT_RCS:
  797. X      print_rcs_script (script);
  798. X      break;
  799. X
  800. X    case OUTPUT_NORMAL:
  801. X      print_normal_script (script);
  802. X      break;
  803. X    }
  804. X
  805. X      finish_output ();
  806. X    }
  807. X
  808. X  for (i = 1; i >= 0; --i)
  809. X    {
  810. X      free (filevec[i].realindexes);
  811. X      free (filevec[i].undiscarded);
  812. X    }
  813. X
  814. X  for (i = 1; i >= 0; --i)
  815. X    free (--filevec[i].changed_flag);
  816. X
  817. X  for (i = 1; i >= 0; --i)
  818. X    free (filevec[i].equivs);
  819. X
  820. X  for (i = 0; i < 2; ++i)
  821. X    {
  822. X      if (filevec[i].buffer != 0)
  823. X    free (filevec[i].buffer);
  824. X      free (filevec[i].linbuf);
  825. X    }
  826. X
  827. X  for (e = script; e; e = p)
  828. X    {
  829. X      p = e->link;
  830. X      free (e);
  831. X    }
  832. X
  833. X  return script ? 1 : 0;
  834. X}
  835. SHAR_EOF
  836. echo "extracting diff/context.c"
  837. sed 's/^X//' << \SHAR_EOF > diff/context.c
  838. X/* Context-format output routines for GNU DIFF.
  839. X   Copyright (C) 1988, 1989 Free Software Foundation, Inc.
  840. X
  841. XThis file is part of GNU DIFF.
  842. X
  843. XGNU DIFF is free software; you can redistribute it and/or modify
  844. Xit under the terms of the GNU General Public License as published by
  845. Xthe Free Software Foundation; either version 1, or (at your option)
  846. Xany later version.
  847. X
  848. XGNU DIFF is distributed in the hope that it will be useful,
  849. Xbut WITHOUT ANY WARRANTY; without even the implied warranty of
  850. XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  851. XGNU General Public License for more details.
  852. X
  853. XYou should have received a copy of the GNU General Public License
  854. Xalong with GNU DIFF; see the file COPYING.  If not, write to
  855. Xthe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  856. X
  857. X#include "diff.h"
  858. X
  859. Xstatic void pr_context_hunk ();
  860. Xstatic struct change *find_hunk ();
  861. Xstatic void mark_ignorable ();
  862. Xstatic int find_function ();
  863. X
  864. X/* Last place find_function started searching from.  */
  865. Xstatic int find_function_last_search;
  866. X
  867. X/* The value find_function returned when it started searching there.  */
  868. Xstatic int find_function_last_match;
  869. X
  870. X/* Print a header for a context diff, with the file names and dates.  */
  871. X
  872. Xvoid
  873. Xprint_context_header (inf)
  874. X     struct file_data *inf;
  875. X{
  876. X  fprintf (outfile, "*** %s\t%s", inf[0].name,
  877. X       ctime (&inf[0].stat.st_mtime));
  878. X  fprintf (outfile, "--- %s\t%s", inf[1].name,
  879. X       ctime (&inf[1].stat.st_mtime));
  880. X}
  881. X
  882. X/* Print an edit script in context format.  */
  883. X
  884. Xvoid
  885. Xprint_context_script (script)
  886. X     struct change *script;
  887. X{
  888. X  if (ignore_blank_lines_flag || ignore_regexp)
  889. X    mark_ignorable (script);
  890. X  else
  891. X    {
  892. X      struct change *e;
  893. X      for (e = script; e; e = e->link)
  894. X    e->ignore = 0;
  895. X    }
  896. X
  897. X  find_function_last_search = 0;
  898. X  find_function_last_match = -1;
  899. X
  900. X  print_script (script, find_hunk, pr_context_hunk);
  901. X}
  902. X
  903. X/* Print a pair of line numbers with a comma, translated for file FILE.
  904. X   If the second number is smaller, use the first in place of it.
  905. X
  906. X   Args A and B are internal line numbers.
  907. X   We print the translated (real) line numbers.  */
  908. X
  909. Xstatic void
  910. Xprint_context_number_range (file, a, b)
  911. X     struct file_data *file;
  912. X     int a, b;
  913. X{
  914. X  int trans_a, trans_b;
  915. X  translate_range (file, a, b, &trans_a, &trans_b);
  916. X
  917. X  /* Note: we can have B < A in the case of a range of no lines.
  918. X     In this case, we should print the line number before the range,
  919. X     which is B.  */
  920. X  if (trans_b >= trans_a)
  921. X    fprintf (outfile, "%d,%d", trans_a, trans_b);
  922. X  else
  923. X    fprintf (outfile, "%d", trans_b);
  924. X}
  925. X
  926. X/* Print a portion of an edit script in context format.
  927. X   HUNK is the beginning of the portion to be printed.
  928. X   The end is marked by a `link' that has been nulled out.
  929. X
  930. X   Prints out lines from both files, and precedes each
  931. X   line with the appropriate flag-character.  */
  932. X
  933. Xstatic void
  934. Xpr_context_hunk (hunk)
  935. X     struct change *hunk;
  936. X{
  937. X  int first0, last0, first1, last1, show_from, show_to, i;
  938. X  struct change *next;
  939. X  char *prefix;
  940. X  char *function;
  941. X  int function_length;
  942. X
  943. X  /* Determine range of line numbers involved in each file.  */
  944. X
  945. X  analyze_hunk (hunk, &first0, &last0, &first1, &last1, &show_from, &show_to);
  946. X
  947. X  if (!show_from && !show_to)
  948. X    return;
  949. X
  950. X  /* Include a context's width before and after.  */
  951. X
  952. X  first0 = max (first0 - context, 0);
  953. X  first1 = max (first1 - context, 0);
  954. X  last0 = min (last0 + context, files[0].buffered_lines - 1);
  955. X  last1 = min (last1 + context, files[1].buffered_lines - 1);
  956. X
  957. X  /* If desired, find the preceding function definition line in file 0.  */
  958. X  function = 0;
  959. X  if (function_regexp)
  960. X    find_function (&files[0], first0, &function, &function_length);
  961. X
  962. X  /* If we looked for and found a function this is part of,
  963. X     include its name in the header of the diff section.  */
  964. X  fprintf (outfile, "***************");
  965. X
  966. X  if (function)
  967. X    {
  968. X      fprintf (outfile, " ");
  969. X      fwrite (function, 1, min (function_length - 1, 40), outfile);
  970. X    }
  971. X
  972. X  fprintf (outfile, "\n*** ");
  973. X  print_context_number_range (&files[0], first0, last0);
  974. X  fprintf (outfile, " ****\n");
  975. X
  976. X  if (show_from)
  977. X    {
  978. X      next = hunk;
  979. X
  980. X      for (i = first0; i <= last0; i++)
  981. X    {
  982. X      /* Skip past changes that apply (in file 0)
  983. X         only to lines before line I.  */
  984. X
  985. X      while (next && next->line0 + next->deleted <= i)
  986. X        next = next->link;
  987. X
  988. X      /* Compute the marking for line I.  */
  989. X
  990. X      prefix = " ";
  991. X      if (next && next->line0 <= i)
  992. X        /* The change NEXT covers this line.
  993. X           If lines were inserted here in file 1, this is "changed".
  994. X           Otherwise it is "deleted".  */
  995. X        prefix = (next->inserted > 0 ? "!" : "-");
  996. X
  997. X      print_1_line (prefix, &files[0].linbuf[i]);
  998. X    }
  999. X    }
  1000. X
  1001. X  fprintf (outfile, "--- ");
  1002. X  print_context_number_range (&files[1], first1, last1);
  1003. X  fprintf (outfile, " ----\n");
  1004. X
  1005. X  if (show_to)
  1006. X    {
  1007. X      next = hunk;
  1008. X
  1009. X      for (i = first1; i <= last1; i++)
  1010. X    {
  1011. X      /* Skip past changes that apply (in file 1)
  1012. X         only to lines before line I.  */
  1013. X
  1014. X      while (next && next->line1 + next->inserted <= i)
  1015. X        next = next->link;
  1016. X
  1017. X      /* Compute the marking for line I.  */
  1018. X
  1019. X      prefix = " ";
  1020. X      if (next && next->line1 <= i)
  1021. X        /* The change NEXT covers this line.
  1022. X           If lines were deleted here in file 0, this is "changed".
  1023. X           Otherwise it is "inserted".  */
  1024. X        prefix = (next->deleted > 0 ? "!" : "+");
  1025. X
  1026. X      print_1_line (prefix, &files[1].linbuf[i]);
  1027. X    }
  1028. X    }
  1029. X}
  1030. X
  1031. X/* Scan a (forward-ordered) edit script for the first place that at least
  1032. X   2*CONTEXT unchanged lines appear, and return a pointer
  1033. X   to the `struct change' for the last change before those lines.  */
  1034. X
  1035. Xstatic struct change *
  1036. Xfind_hunk (start)
  1037. X     struct change *start;
  1038. X{
  1039. X  struct change *prev;
  1040. X  int top0, top1;
  1041. X  int thresh;
  1042. X
  1043. X  do
  1044. X    {
  1045. X      /* Computer number of first line in each file beyond this changed.  */
  1046. X      top0 = start->line0 + start->deleted;
  1047. X      top1 = start->line1 + start->inserted;
  1048. X      prev = start;
  1049. X      start = start->link;
  1050. X      /* Threshold distance is 2*CONTEXT between two non-ignorable changes,
  1051. X     but only CONTEXT if one is ignorable.  */
  1052. X      thresh = ((prev->ignore || (start && start->ignore))
  1053. X        ? context
  1054. X        : 2 * context);
  1055. X      /* It is not supposed to matter which file we check in the end-test.
  1056. X     If it would matter, crash.  */
  1057. X      if (start && start->line0 - top0 != start->line1 - top1)
  1058. X    abort ();
  1059. X    } while (start
  1060. X         /* Keep going if less than THRESH lines
  1061. X        elapse before the affected line.  */
  1062. X         && start->line0 < top0 + thresh);
  1063. X
  1064. X  return prev;
  1065. X}
  1066. X
  1067. X/* Set the `ignore' flag properly in each change in SCRIPT.
  1068. X   It should be 1 if all the lines inserted or deleted in that change
  1069. X   are ignorable lines.  */
  1070. X
  1071. Xstatic void
  1072. Xmark_ignorable (script)
  1073. X     struct change *script;
  1074. X{
  1075. X  while (script)
  1076. X    {
  1077. X      struct change *next = script->link;
  1078. X      int first0, last0, first1, last1, deletes, inserts;
  1079. X
  1080. X      /* Turn this change into a hunk: detach it from the others.  */
  1081. X      script->link = 0;
  1082. X
  1083. X      /* Determine whether this change is ignorable.  */
  1084. X      analyze_hunk (script, &first0, &last0, &first1, &last1, &deletes, &inserts);
  1085. X      /* Reconnect the chain as before.  */
  1086. X      script->link = next;
  1087. X
  1088. X      /* If the change is ignorable, mark it.  */
  1089. X      script->ignore = (!deletes && !inserts);
  1090. X
  1091. X      /* Advance to the following change.  */
  1092. X      script = next;
  1093. X    }
  1094. X}
  1095. X
  1096. X/* Find the last function-header line in FILE prior to line number LINENUM.
  1097. X   This is a line containing a match for the regexp in `function_regexp'.
  1098. X   Store the address of the line text into LINEP and the length of the
  1099. X   line into LENP.
  1100. X   Do not store anything if no function-header is found.  */
  1101. X
  1102. Xstatic int
  1103. Xfind_function (file, linenum, linep, lenp)
  1104. X     struct file_data *file;
  1105. X     int linenum;
  1106. X     char **linep;
  1107. X     int *lenp;
  1108. X{
  1109. X  int i = linenum;
  1110. X  int last = find_function_last_search;
  1111. X  find_function_last_search = i;
  1112. X
  1113. X  while (--i >= last)
  1114. X    {
  1115. X      /* See if this line is what we want.  */
  1116. X
  1117. X      if (0 <= re_search (&function_regexp_compiled,
  1118. X              files[0].linbuf[i].text,
  1119. X              files[0].linbuf[i].length,
  1120. X              0, files[0].linbuf[i].length,
  1121. X              0))
  1122. X    {
  1123. X      *linep = files[0].linbuf[i].text;
  1124. X      *lenp = files[0].linbuf[i].length;
  1125. X      find_function_last_match = i;
  1126. X      return 1;
  1127. X    }
  1128. X    }
  1129. X  /* If we search back to where we started searching the previous time,
  1130. X     find the line we found last time.  */
  1131. X  if (find_function_last_match >= 0)
  1132. X    {
  1133. X      i = find_function_last_match;
  1134. X      *linep = files[0].linbuf[i].text;
  1135. X      *lenp = files[0].linbuf[i].length;
  1136. X      return 1;
  1137. X    }
  1138. X  return 0;
  1139. X}
  1140. SHAR_EOF
  1141. echo "extracting diff/diff.c"
  1142. sed 's/^X//' << \SHAR_EOF > diff/diff.c
  1143. X/* GNU DIFF main routine.
  1144. X   Copyright (C) 1988, 1989 Free Software Foundation, Inc.
  1145. X
  1146. XThis file is part of GNU DIFF.
  1147. X
  1148. XGNU DIFF is free software; you can redistribute it and/or modify
  1149. Xit under the terms of the GNU General Public License as published by
  1150. Xthe Free Software Foundation; either version 1, or (at your option)
  1151. Xany later version.
  1152. X
  1153. XGNU DIFF is distributed in the hope that it will be useful,
  1154. Xbut WITHOUT ANY WARRANTY; without even the implied warranty of
  1155. XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  1156. XGNU General Public License for more details.
  1157. X
  1158. XYou should have received a copy of the GNU General Public License
  1159. Xalong with GNU DIFF; see the file COPYING.  If not, write to
  1160. Xthe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  1161. X
  1162. X/* GNU DIFF was written by Mike Haertel, David Hayes,
  1163. X   Richard Stallman and Len Tower.  */
  1164. X
  1165. X#define GDIFF_MAIN
  1166. X#include "regex.h"
  1167. X#include "diff.h"
  1168. X
  1169. X
  1170. X/* Nonzero for -r: if comparing two directories,
  1171. X   compare their common subdirectories recursively.  */
  1172. X
  1173. Xint recursive;
  1174. X
  1175. X/* For debugging: don't do discard_confusing_lines.  */
  1176. X
  1177. Xint no_discards;
  1178. X
  1179. Xvoid specify_style();
  1180. X
  1181. X/* Return a string containing the command options with which diff was invoked.
  1182. X   Spaces appear between what were separate ARGV-elements.
  1183. X   There is a space at the beginning but none at the end.
  1184. X   If there were no options, the result is an empty string.
  1185. X
  1186. X   Arguments: VECTOR, a vector containing separate ARGV-elements, and COUNT,
  1187. X   the length of that vector.  */
  1188. X
  1189. Xstatic char *
  1190. Xoption_list (vector, count)
  1191. X     char **vector;
  1192. X     int count;
  1193. X{
  1194. X  int i;
  1195. X  int length = 0;
  1196. X  char *result;
  1197. X
  1198. X  for (i = 0; i < count; i++)
  1199. X    length += strlen (vector[i]) + 1;
  1200. X
  1201. X  result = (char *) xmalloc (length + 1);
  1202. X  result[0] = 0;
  1203. X
  1204. X  for (i = 0; i < count; i++)
  1205. X    {
  1206. X      strcat (result, " ");
  1207. X      strcat (result, vector[i]);
  1208. X    }
  1209. X
  1210. X  return result;
  1211. X}
  1212. X
  1213. Xmain (argc, argv)
  1214. X     int argc;
  1215. X     char *argv[];
  1216. X{
  1217. X  int val;
  1218. X  int c;
  1219. X  int prev = -1;
  1220. X
  1221. X  extern int optind;
  1222. X  extern char *optarg;
  1223. X
  1224. X  program = argv[0];
  1225. X
  1226. X  /* Do our initializations. */
  1227. X  output_style = OUTPUT_NORMAL;
  1228. X  always_text_flag = FALSE;
  1229. X  ignore_space_change_flag = FALSE;
  1230. X  ignore_all_space_flag = FALSE;
  1231. X  length_varies = FALSE;
  1232. X  ignore_case_flag = FALSE;
  1233. X  ignore_blank_lines_flag = FALSE;
  1234. X  ignore_regexp = 0;
  1235. X  function_regexp = 0;
  1236. X  print_file_same_flag = FALSE;
  1237. X  entire_new_file_flag = FALSE;
  1238. X  context = -1;
  1239. X  line_end_char = '\n';
  1240. X  tab_align_flag = FALSE;
  1241. X  tab_expand_flag = FALSE;
  1242. X  recursive = FALSE;
  1243. X  paginate_flag = FALSE;
  1244. X  heuristic = FALSE;
  1245. X  dir_start_file = NULL;
  1246. X  msg_chain = NULL;
  1247. X  msg_chain_end = NULL;
  1248. X  no_discards = 0;
  1249. X
  1250. X  /* Decode the options.  */
  1251. X
  1252. X  while ((c = getopt (argc, argv, "0123456789abBcC:defF:hHiI:lnNprsS:tTw"))
  1253. X     != EOF)
  1254. X    {
  1255. X      switch (c)
  1256. X    {
  1257. X      /* All digits combine in decimal to specify the context-size.  */
  1258. X    case '1':
  1259. X    case '2':
  1260. X    case '3':
  1261. X    case '4':
  1262. X    case '5':
  1263. X    case '6':
  1264. X    case '7':
  1265. X    case '8':
  1266. X    case '9':
  1267. X    case '0':
  1268. X      if (context == -1)
  1269. X        context = 0;
  1270. X      /* If a context length has already been specified,
  1271. X         more digits allowed only if they follow right after the others.
  1272. X         Reject two separate runs of digits, or digits after -C.  */
  1273. X      else if (prev < '0' || prev > '9')
  1274. X        fatal ("context length specified twice");
  1275. X
  1276. X      context = context * 10 + c - '0';
  1277. X      break;
  1278. X
  1279. X    case 'a':
  1280. X      /* Treat all files as text files; never treat as binary.  */
  1281. X      always_text_flag = 1;
  1282. X      break;
  1283. X
  1284. X    case 'b':
  1285. X      /* Ignore changes in amount of whitespace.  */
  1286. X      ignore_space_change_flag = 1;
  1287. X      length_varies = 1;
  1288. X      break;
  1289. X
  1290. X    case 'B':
  1291. X      /* Ignore changes affecting only blank lines.  */
  1292. X      ignore_blank_lines_flag = 1;
  1293. X      break;
  1294. X
  1295. X    case 'c':
  1296. X      /* Make context-style output.  */
  1297. X      specify_style (OUTPUT_CONTEXT);
  1298. X      break;
  1299. X
  1300. X    case 'C':
  1301. X      if (context >= 0)
  1302. X        fatal ("context length specified twice");
  1303. X      {
  1304. X        char *p;
  1305. X        for (p = optarg; *p; p++)
  1306. X          if (*p < '0' || *p > '9')
  1307. X        fatal ("invalid context length argument (-C option)");
  1308. X      }
  1309. X      context = atoi (optarg);
  1310. X      break;
  1311. X
  1312. X    case 'd':
  1313. X      /* Don't discard lines.  This makes things slower (sometimes much
  1314. X         slower) but will find a guaranteed minimal set of changes.  */
  1315. X      no_discards = 1;
  1316. X      break;
  1317. X
  1318. X    case 'e':
  1319. X      /* Make output that is a valid `ed' script.  */
  1320. X      specify_style (OUTPUT_ED);
  1321. X      break;
  1322. X
  1323. X    case 'f':
  1324. X      /* Make output that looks vaguely like an `ed' script
  1325. X         but has changes in the order they appear in the file.  */
  1326. X      specify_style (OUTPUT_FORWARD_ED);
  1327. X      break;
  1328. X
  1329. X    case 'F':
  1330. X      /* Show, for each set of changes, the previous line that
  1331. X         matches the specified regexp.  Currently affects only
  1332. X         context-style output.  */
  1333. X      function_regexp = optarg;
  1334. X      break;
  1335. X
  1336. X    case 'h':
  1337. X      /* Split the files into chunks of around 1500 lines
  1338. X         for faster processing.  Usually does not change the result.
  1339. X
  1340. X         This currently has no effect.  */
  1341. X      break;
  1342. X
  1343. X    case 'H':
  1344. X      /* Turn on heuristics that speed processing of large files
  1345. X         with a small density of changes.  */
  1346. X      heuristic = 1;
  1347. X      break;
  1348. X
  1349. X    case 'i':
  1350. X      /* Ignore changes in case.  */
  1351. X      ignore_case_flag = 1;
  1352. X      break;
  1353. X
  1354. X    case 'I':
  1355. X      /* Ignore changes affecting only lines that match the
  1356. X         specified regexp.  */
  1357. X      ignore_regexp = optarg;
  1358. X      break;
  1359. X
  1360. X    case 'l':
  1361. X      /* Pass the output through `pr' to paginate it.  */
  1362. X      paginate_flag = 1;
  1363. X      break;
  1364. X
  1365. X    case 'n':
  1366. X      /* Output RCS-style diffs, like `-f' except that each command
  1367. X         specifies the number of lines affected.  */
  1368. X      specify_style (OUTPUT_RCS);
  1369. X      break;
  1370. X
  1371. X    case 'N':
  1372. X      /* When comparing directories, if a file appears only in one
  1373. X         directory, treat it as present but empty in the other.  */
  1374. X      entire_new_file_flag = 1;
  1375. X      break;
  1376. X
  1377. X    case 'p':
  1378. X      /* Make context-style output and show name of last C function.  */
  1379. X      specify_style (OUTPUT_CONTEXT);
  1380. X      function_regexp = "^[_a-zA-Z]";
  1381. X      break;
  1382. X
  1383. X    case 'r':
  1384. X      /* When comparing directories, 
  1385. X         recursively compare any subdirectories found.  */
  1386. X      recursive = 1;
  1387. X      break;
  1388. X
  1389. X    case 's':
  1390. X      /* Print a message if the files are the same.  */
  1391. X      print_file_same_flag = 1;
  1392. X      break;
  1393. X
  1394. X    case 'S':
  1395. X      /* When comparing directories, start with the specified
  1396. X         file name.  This is used for resuming an aborted comparison.  */
  1397. X      dir_start_file = optarg;
  1398. X      break;
  1399. X
  1400. X    case 't':
  1401. X      /* Expand tabs to spaces in the output so that it preserves
  1402. X         the alignment of the input files.  */
  1403. X      tab_expand_flag = 1;
  1404. X      break;
  1405. X
  1406. X    case 'T':
  1407. X      /* Use a tab in the output, rather than a space, before the
  1408. X         text of an input line, so as to keep the proper alignment
  1409. X         in the input line without changing the characters in it.  */
  1410. X      tab_align_flag = 1;
  1411. X      break;
  1412. X
  1413. X    case 'w':
  1414. X      /* Ignore horizontal whitespace when comparing lines.  */
  1415. X      ignore_all_space_flag = 1;
  1416. X      length_varies = 1;
  1417. X      break;
  1418. X    }
  1419. X      prev = c;
  1420. X    }
  1421. X
  1422. X  if (optind != argc - 2)
  1423. X    fatal ("requires two file names.  Usage: diff [-options] file1 file2");
  1424. X
  1425. X  /*
  1426. X   * @@ need more complicated usage string for directory options??
  1427. X   * Note three liner at top of BSD documentation, and John Gilmore
  1428. X   * message in his public domain tar being used by GNU.  
  1429. X   */
  1430. X
  1431. X  if (ignore_regexp)
  1432. X    {
  1433. X      char *val;
  1434. X      bzero (&ignore_regexp_compiled, sizeof ignore_regexp_compiled);
  1435. X      val = re_compile_pattern (ignore_regexp, strlen (ignore_regexp),
  1436. X                &ignore_regexp_compiled);
  1437. X      if (val != 0)
  1438. X    error ("-I option: ", val);
  1439. X      ignore_regexp_compiled.fastmap = (char *) xmalloc (256);
  1440. X    }
  1441. X
  1442. X  if (function_regexp)
  1443. X    {
  1444. X      char *val;
  1445. X      bzero (&function_regexp_compiled, sizeof function_regexp_compiled);
  1446. X      val = re_compile_pattern (function_regexp, strlen (function_regexp),
  1447. X                &function_regexp_compiled);
  1448. X      if (val != 0)
  1449. X    error ("-F option: ", val);
  1450. X      function_regexp_compiled.fastmap = (char *) xmalloc (256);
  1451. X    }
  1452. X
  1453. X  if (output_style != OUTPUT_CONTEXT)
  1454. X    context = 0;
  1455. X  else if (context == -1)
  1456. X    /* Default amount of context for -c.  */
  1457. X    context = 3;
  1458. X
  1459. X  switch_string = option_list (argv + 1, optind - 1);
  1460. X
  1461. X  val = compare_files (0, argv[optind], 0, argv[optind + 1], 0);
  1462. X
  1463. X  /* Print any messages that were saved up for last.  */
  1464. X  print_message_queue ();
  1465. X
  1466. X  exit (val);
  1467. X}
  1468. X
  1469. Xvoid specify_style (style)
  1470. X     enum output_style style;
  1471. X{
  1472. X  if (output_style != OUTPUT_NORMAL
  1473. X      && output_style != style)
  1474. X    error ("conflicting specifications of output style");
  1475. X  output_style = style;
  1476. X}
  1477. X
  1478. X/* Compare two files (or dirs) with specified names
  1479. X   DIR0/NAME0 and DIR1/NAME1, at level DEPTH in directory recursion.
  1480. X   (if DIR0 is 0, then the name is just NAME0, etc.)
  1481. X   This is self-contained; it opens the files and closes them.
  1482. X
  1483. X   Value is 0 if files are identical, 1 if different,
  1484. X   2 if there is a problem opening them.  */
  1485. X
  1486. Xint
  1487. Xcompare_files (dir0, name0, dir1, name1, depth)
  1488. X     char *dir0, *dir1;
  1489. X     char *name0, *name1;
  1490. X     int depth;
  1491. X{
  1492. X  struct file_data inf[2];
  1493. X  register int i;
  1494. X  int val;
  1495. X  int errorcount = 0;
  1496. X  int stat_result[2];
  1497. X
  1498. X  /* If this is directory comparison, perhaps we have a file
  1499. X     that exists only in one of the directories.
  1500. X     If so, just print a message to that effect.  */
  1501. X
  1502. X  if (! entire_new_file_flag && (name0 == 0 || name1 == 0))
  1503. X    {
  1504. X      char *name = name0 == 0 ? name1 : name0;
  1505. X      char *dir = name0 == 0 ? dir1 : dir0;
  1506. X      message ("Only in %s: %s\n", dir, name);
  1507. X      /* Return 1 so that diff_dirs will return 1 ("some files differ").  */
  1508. X      return 1;
  1509. X    }
  1510. X
  1511. X  /* Mark any nonexistent file with -1 in the desc field.  */
  1512. X
  1513. X  inf[0].desc = name0 == 0 ? -1 : 0;
  1514. X  inf[1].desc = name1 == 0 ? -1 : 0;
  1515. X
  1516. X  /* Now record the full name of each file, including nonexistent ones.  */
  1517. X
  1518. X  if (name0 == 0)
  1519. X    name0 = name1;
  1520. X  if (name1 == 0)
  1521. X    name1 = name0;
  1522. X
  1523. X  inf[0].name = dir0 == 0 ? name0 : concat (dir0, "/", name0);
  1524. X  inf[1].name = dir1 == 0 ? name1 : concat (dir1, "/", name1);
  1525. X
  1526. X  /* Stat the files.  Record whether they are directories.
  1527. X     Record in stat_result whether stat fails.  */
  1528. X
  1529. X  for (i = 0; i <= 1; i++)
  1530. X    {
  1531. X      inf[i].stat.st_size = 0;
  1532. X      inf[i].stat.st_mtime = 0;
  1533. X      inf[i].dir_p = 0;
  1534. X      stat_result[i] = 0;
  1535. X
  1536. X      if (inf[i].desc != -1
  1537. X      && strcmp (inf[i].name, "-"))
  1538. X    {
  1539. X      char *filename = inf[i].name;
  1540. X
  1541. X      stat_result[i] = stat (filename, &inf[i].stat);
  1542. X      if (stat_result[i] < 0)
  1543. X        {
  1544. X          perror_with_name (filename);
  1545. X          errorcount = 1;
  1546. X        }
  1547. X      else
  1548. X#ifdef AMIGA
  1549. X        inf[i].dir_p = (inf[i].stat.st_type > 0);
  1550. X#else
  1551. X        inf[i].dir_p = (S_IFDIR == (inf[i].stat.st_mode & S_IFMT));
  1552. X#endif
  1553. X    }
  1554. X    }
  1555. X
  1556. X  /* See if the two named files are actually the same physical file.
  1557. X     If so, we know they are identical without actually reading them.  */
  1558. X
  1559. X#ifndef AMIGA
  1560. X  if (inf[0].stat.st_ino == inf[1].stat.st_ino
  1561. X      && inf[0].stat.st_dev == inf[1].stat.st_dev
  1562. X      && stat_result[0] == 0
  1563. X      && stat_result[1] == 0)
  1564. X    {
  1565. X      val = 0;
  1566. X      goto done;
  1567. X    }
  1568. X#endif
  1569. X
  1570. X  if (name0 == 0)
  1571. X    inf[0].dir_p = inf[1].dir_p;
  1572. X  if (name1 == 0)
  1573. X    inf[1].dir_p = inf[0].dir_p;
  1574. X
  1575. X  /* Open the files and record their descriptors.  */
  1576. X
  1577. X  for (i = 0; i <= 1; i++)
  1578. X    {
  1579. X      if (inf[i].desc == -1)
  1580. X    ;
  1581. X      else if (!strcmp (inf[i].name, "-"))
  1582. X    {
  1583. X      inf[i].desc = fileno(stdin);
  1584. X      inf[i].name = "Standard Input";
  1585. X#ifdef AMIGA
  1586. X      inf[i].stat.st_type = -1;
  1587. X#endif
  1588. X    }
  1589. X      /* Don't bother opening if stat already failed.  */
  1590. X      else if (stat_result[i] == 0 && ! inf[i].dir_p)
  1591. X    {
  1592. X      char *filename = inf[i].name;
  1593. X
  1594. X      inf[i].desc = open (filename, O_RDONLY, 0);
  1595. X      if (0 > inf[i].desc)
  1596. X        {
  1597. X          perror_with_name (filename);
  1598. X          errorcount = 1;
  1599. X        }
  1600. X    }
  1601. X    }
  1602. X
  1603. X  if (errorcount)
  1604. X    {
  1605. X
  1606. X      /* If either file should exist but fails to be opened, return 2.  */
  1607. X
  1608. X      val = 2;
  1609. X
  1610. X    }
  1611. X  else if (inf[0].dir_p && inf[1].dir_p)
  1612. X    {
  1613. X
  1614. X      /* If both are directories, compare the files in them.  */
  1615. X
  1616. X      if (depth > 0 && !recursive)
  1617. X    {
  1618. X      /* But don't compare dir contents one level down
  1619. X         unless -r was specified.  */
  1620. X      message ("Common subdirectories: %s and %s\n",
  1621. X           inf[0].name, inf[1].name);
  1622. X      val = 0;
  1623. X    }
  1624. X      else
  1625. X    {
  1626. X      val = diff_dirs (inf[0].name, inf[1].name, 
  1627. X               compare_files, depth, 0, 0);
  1628. X    }
  1629. X
  1630. X    }
  1631. X  else if (depth == 0 && (inf[0].dir_p || inf[1].dir_p))
  1632. X    {
  1633. X
  1634. X      /* If only one is a directory, and it was specified in the command line,
  1635. X     use the file in that dir whose basename matches the other file.  */
  1636. X
  1637. X      int dir_arg = (inf[0].dir_p ? 0 : 1);
  1638. X      int fnm_arg = (inf[0].dir_p ? 1 : 0);
  1639. X      char *p = strrchr(inf[fnm_arg].name, '/');
  1640. X      char *filename = concat (inf[dir_arg].name,  "/",
  1641. X                   (p ? p+1 : inf[fnm_arg].name));
  1642. X
  1643. X#ifdef AMIGA
  1644. X      inf[dir_arg].dir_p = (getfa(filename) == 1);
  1645. X      if (!inf[dir_arg].dir_p)
  1646. X        {
  1647. X        if (stat (filename,&inf[dir_arg].stat) < 0)
  1648. X      pfatal_with_name (filename);
  1649. X        inf[dir_arg].desc = open (filename, O_RDONLY, 0);
  1650. X        if (0 > inf[dir_arg].desc)
  1651. X          {
  1652. X            perror_with_name (filename);
  1653. X            val = 2;
  1654. X          }
  1655. X/*    free (inf[dir_arg].name); */
  1656. X    inf[dir_arg].name = filename;
  1657. X    val = diff_2_files (inf, depth);
  1658. X        }
  1659. X      else
  1660. X    {
  1661. X      error ("%s is a directory but %s is not",
  1662. X       inf[dir_arg].name, inf[fnm_arg].name);
  1663. X      val = 2;
  1664. X    }
  1665. X#else
  1666. X      inf[dir_arg].desc = open (filename, O_RDONLY, 0);
  1667. X
  1668. X      if (0 > inf[dir_arg].desc)
  1669. X    {
  1670. X      perror_with_name (filename);
  1671. X      val = 2;
  1672. X    }
  1673. X      else
  1674. X    {
  1675. X      /* JF: patch from the net to check and make sure we can really free
  1676. X         this.  If it's from argv[], freeing it is a *really* bad idea */
  1677. X      if (0 != (dir_arg ? dir1 : dir0))
  1678. X        free (inf[dir_arg].name);
  1679. X      inf[dir_arg].name = filename;
  1680. X      if (fstat (inf[dir_arg].desc, &inf[dir_arg].stat) < 0)
  1681. X        pfatal_with_name (inf[dir_arg].name);
  1682. X
  1683. X      inf[dir_arg].dir_p
  1684. X        = (S_IFDIR == (inf[dir_arg].stat.st_mode & S_IFMT));
  1685. X      if (inf[dir_arg].dir_p)
  1686. X        {
  1687. X          error ("%s is a directory but %s is not",
  1688. X             inf[dir_arg].name, inf[fnm_arg].name);
  1689. X          val = 1;
  1690. X        }
  1691. X      else
  1692. X        val = diff_2_files (inf, depth);
  1693. X    }
  1694. X#endif
  1695. X    }
  1696. X  else if (depth > 0 && (inf[0].dir_p || inf[1].dir_p))
  1697. X    {
  1698. X      /* Perhaps we have a subdirectory that exists only in one directory.
  1699. X     If so, just print a message to that effect.  */
  1700. X
  1701. X      if (inf[0].desc == -1 || inf[1].desc == -1)
  1702. X    {
  1703. X      if (entire_new_file_flag && recursive)
  1704. X        val = diff_dirs (inf[0].name, inf[1].name, compare_files, depth,
  1705. X                 inf[0].desc == -1, inf[1].desc == -1);
  1706. X      else
  1707. X        {
  1708. X          char *dir = (inf[0].desc == -1) ? dir1 : dir0;
  1709. X          message ("Only in %s: %s\n", dir, name0);
  1710. X          val = 1;
  1711. X        }
  1712. X    }
  1713. X      else
  1714. X    {
  1715. X      /* We have a subdirectory in one directory
  1716. X         and a file in the other.  */
  1717. X
  1718. X      if (inf[0].dir_p)
  1719. X        message ("%s is a directory but %s is not\n",
  1720. X             inf[0].name, inf[1].name);
  1721. X      else
  1722. X        message ("%s is a directory but %s is not\n",
  1723. X             inf[1].name, inf[0].name);
  1724. X      /* This is a difference.  */
  1725. X      val = 1;
  1726. X    }
  1727. X    }
  1728. X  else
  1729. X    {
  1730. X
  1731. X      /* Both exist and both are ordinary files.  */
  1732. X
  1733. X      val = diff_2_files (inf, depth);
  1734. X
  1735. X    }
  1736. X
  1737. X  /* Now the comparison has been done, if no error prevented it,
  1738. X     and VAL is the value this function will return.  */
  1739. X
  1740. X  if (inf[0].desc > 0)
  1741. X    close (inf[0].desc);
  1742. X  if (inf[1].desc > 0)
  1743. X    close (inf[1].desc);
  1744. X
  1745. X done:
  1746. X  if (val == 0 && print_file_same_flag && !inf[0].dir_p)
  1747. X    message ("Files %s and %s are identical\n",
  1748. X         inf[0].name, inf[1].name);
  1749. X
  1750. X  fflush (stdout);
  1751. X
  1752. X  if (dir0 != 0)
  1753. X    free (inf[0].name);
  1754. X  if (dir1 != 0)
  1755. X    free (inf[1].name);
  1756. X
  1757. X  return val;
  1758. X}
  1759. SHAR_EOF
  1760. echo "extracting diff/diff3.c"
  1761. sed 's/^X//' << \SHAR_EOF > diff/diff3.c
  1762. X/* Three-way file comparison program (diff3) for Project GNU
  1763. X   Copyright (C) 1988, 1989 Free Software Foundation, Inc.
  1764. X
  1765. X   This program is free software; you can redistribute it and/or modify
  1766. X   it under the terms of the GNU General Public License as published by
  1767. X   the Free Software Foundation; either version 1, or (at your option)
  1768. X   any later version.
  1769. X
  1770. X   This program is distributed in the hope that it will be useful,
  1771. X   but WITHOUT ANY WARRANTY; without even the implied warranty of
  1772. X   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  1773. X   GNU General Public License for more details.
  1774. X
  1775. X   You should have received a copy of the GNU General Public License
  1776. X   along with this program; if not, write to the Free Software
  1777. X   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  1778. X
  1779. X
  1780. X/* Written by Randy Smith */
  1781. X
  1782. X/* 
  1783. X * Include files.
  1784. X */
  1785. X#include <stdio.h>
  1786. X#include <ctype.h>
  1787. X
  1788. X#if defined(USG) || defined(AMIGA)
  1789. X/* Define needed BSD functions in terms of sysV library.  */
  1790. X
  1791. X#define bcopy(s,d,n)    memcpy((d),(s),(n))
  1792. X#define bcmp(s1,s2,n)    memcmp((s1),(s2),(n))
  1793. X#define bzero(s,n)    memset((s),0,(n))
  1794. X#endif
  1795. X
  1796. X#ifdef USG
  1797. X#define dup2(f,t)    (close(t),fcntl((f),F_DUPFD,(t)))
  1798. X
  1799. X#define vfork    fork
  1800. X#define index    strchr
  1801. X#define rindex    strrchr
  1802. X#endif
  1803. X/*
  1804. X * Internal data structures and macros for the diff3 program; includes
  1805. X * data structures for both diff3 diffs and normal diffs.
  1806. X */
  1807. X
  1808. X/*
  1809. X * Different files within a diff
  1810. X */
  1811. X#define    FILE0    0
  1812. X#define    FILE1    1
  1813. X#define    FILE2    2
  1814. X
  1815. X/*
  1816. X * Three way diffs are build out of two two-way diffs; the file which
  1817. X * the two two-way diffs share is:
  1818. X */
  1819. X#define    FILEC    FILE0
  1820. X
  1821. X/* The ranges are indexed by */
  1822. X#define    START    0
  1823. X#define    END    1
  1824. X
  1825. Xenum diff_type {
  1826. X  ERROR,            /* Should not be used */
  1827. X  ADD,                /* Two way diff add */
  1828. X  CHANGE,            /* Two way diff change */
  1829. X  DELETE,            /* Two way diff delete */
  1830. X  DIFF_ALL,            /* All three are different */
  1831. X  DIFF_1ST,            /* Only the first is different */
  1832. X  DIFF_2ND,            /* Only the second */
  1833. X  DIFF_3RD            /* Only the third */
  1834. X};
  1835. X
  1836. X/* Two-way diff */
  1837. Xstruct diff_block {
  1838. X  int ranges[2][2];            /* Ranges are inclusive */
  1839. X  char **lines[2];        /* The actual lines (may contain nulls) */
  1840. X  int *lengths[2];        /* The lengths of the lines (since nulls) */
  1841. X  struct diff_block *next;
  1842. X};
  1843. X
  1844. X/* Three-way diff */
  1845. X
  1846. Xstruct diff3_block {
  1847. X  enum diff_type correspond;    /* Type of diff */
  1848. X  int ranges[3][2];            /* Ranges are inclusive */
  1849. X  char **lines[3];        /* The actual lines (may contain nulls) */
  1850. X  int *lengths[3];        /* The lengths of the lines (since nulls) */
  1851. X  struct diff3_block *next;
  1852. X};
  1853. X
  1854. X/*
  1855. X * Access the ranges on a diff block.
  1856. X */
  1857. X#define    D_LOWLINE(diff, filenum)    \
  1858. X  ((diff)->ranges[filenum][START])
  1859. X#define    D_HIGHLINE(diff, filenum)    \
  1860. X  ((diff)->ranges[filenum][END])
  1861. X#define    D_NUMLINES(diff, filenum)    \
  1862. X  (D_HIGHLINE((diff), (filenum)) - D_LOWLINE((diff), (filenum)) + 1)
  1863. X
  1864. X/*
  1865. X * Access the line numbers in a file in a diff by absolute line number
  1866. X * (i.e. line number within the original file).  Note that these are
  1867. X * lvalues and can be used for assignment.
  1868. X */
  1869. X#define    D_LINENUM(diff, filenum, linenum)    \
  1870. X  (*((diff)->lines[filenum] + linenum - D_LOWLINE((diff), (filenum))))
  1871. X#define    D_LINELEN(diff, filenum, linenum)    \
  1872. X  (*((diff)->lengths[filenum] + linenum - D_LOWLINE((diff), (filenum))))
  1873. X
  1874. X/*
  1875. X * Access the line numbers in a file in a diff by relative line
  1876. X * numbers (i.e. line number within the diff itself).  Note that these
  1877. X * are lvalues and can be used for assignment.
  1878. X */
  1879. X#define    D_RELNUM(diff, filenum, linenum)    \
  1880. X  (*((diff)->lines[filenum] + linenum))
  1881. X#define    D_RELLEN(diff, filenum, linenum)    \
  1882. X  (*((diff)->lengths[filenum] + linenum))
  1883. X
  1884. X/*
  1885. X * And get at them directly, when that should be necessary.
  1886. X */
  1887. X#define    D_LINEARRAY(diff, filenum)    \
  1888. X  ((diff)->lines[filenum])
  1889. X#define    D_LENARRAY(diff, filenum)    \
  1890. X  ((diff)->lengths[filenum])
  1891. X
  1892. X/*
  1893. X * Next block.
  1894. X */
  1895. X#define    D_NEXT(diff)    ((diff)->next)
  1896. X
  1897. X/*
  1898. X * Access the type of a diff3 block.
  1899. X */
  1900. X#define    D3_TYPE(diff)    ((diff)->correspond)
  1901. X
  1902. X/*
  1903. X * Line mappings based on diffs.  The first maps off the top of the
  1904. X * diff, the second off of the bottom.
  1905. X */
  1906. X#define    D_HIGH_MAPLINE(diff, fromfile, tofile, lineno)    \
  1907. X  ((lineno)                        \
  1908. X   - D_HIGHLINE ((diff), (fromfile))            \
  1909. X   + D_HIGHLINE ((diff), (tofile)))
  1910. X
  1911. X#define    D_LOW_MAPLINE(diff, fromfile, tofile, lineno)    \
  1912. X  ((lineno)                        \
  1913. X   - D_LOWLINE ((diff), (fromfile))            \
  1914. X   + D_LOWLINE ((diff), (tofile)))
  1915. X
  1916. X/*
  1917. X * General memory allocation function.
  1918. X */
  1919. X#define    ALLOCATE(number, type)    \
  1920. X  (type *) xmalloc ((number) * sizeof (type))
  1921. X
  1922. X/*
  1923. X * Options variables for flags set on command line.
  1924. X *
  1925. X * EDSCRIPT: Write out an ed script instead of the standard diff3 format.
  1926. X *
  1927. X * FLAGGING: Indicates that in the case of overlapping diffs (type
  1928. X * DIFF_ALL), the lines which would normally be deleted from file 1
  1929. X * should be preserved with a special flagging mechanism.
  1930. X *
  1931. X * DONT_WRITE_OVERLAP: 1 if information for overlapping diffs should
  1932. X * not be output.
  1933. X *
  1934. X * DONT_WRITE_SIMPLE: 1 if information for non-overlapping diffs
  1935. X * should not be output. 
  1936. X *
  1937. X * FINALWRITE: 1 if a :wq should be included at the end of the script
  1938. X * to write out the file being edited.
  1939. X */
  1940. X#define DIFF_PROGRAM "rcs:diff"
  1941. X
  1942. Xint edscript;
  1943. Xint flagging;
  1944. Xint dont_write_overlap;
  1945. Xint dont_write_simple;
  1946. Xint finalwrite;
  1947. Xint overlaps; 
  1948. Xextern int optind;
  1949. X
  1950. Xchar *argv0;
  1951. X
  1952. X/*
  1953. X * Forward function declarations.
  1954. X */
  1955. Xstruct diff_block *process_diff ();
  1956. Xstruct diff3_block *make_3way_diff ();
  1957. Xvoid output_diff3 ();
  1958. Xvoid output_diff3_edscript ();
  1959. Xvoid usage ();
  1960. Xvoid fatal ();
  1961. Xvoid perror_with_exit ();
  1962. Xstruct diff3_block *using_to_diff3_block ();
  1963. Xint copy_stringlist ();
  1964. Xstruct diff3_block *create_diff3_block ();
  1965. Xint compare_line_list ();
  1966. X
  1967. Xint read_diff ();
  1968. Xenum diff_type process_diff_control ();
  1969. Xchar *scan_diff_line ();
  1970. X
  1971. Xstruct diff3_block *reverse_diff3_blocklist ();
  1972. X
  1973. Xvoid *xmalloc ();
  1974. Xvoid *xrealloc ();
  1975. X
  1976. X/*
  1977. X * No options take arguments.  "i" is my own addition; it stands for
  1978. X * "include write command", to emulate system V behavior.
  1979. X */
  1980. X#define    ARGSTRING    "eix3EX"
  1981. X
  1982. Xchar diff_program[] = DIFF_PROGRAM;
  1983. X
  1984. X/*
  1985. X * Main program.  Calls diff twice on two pairs of input files,
  1986. X * combines the two diffs, and outputs them.
  1987. X */
  1988. Xmain (argc, argv)
  1989. X     int argc;
  1990. X     char **argv;
  1991. X{
  1992. X  int c;
  1993. X  int mapping [3];
  1994. X  int shiftmap;
  1995. X  int incompat;
  1996. X  struct diff_block *thread1, *thread2;
  1997. X  struct diff3_block *diff;
  1998. X
  1999. X  edscript = flagging = dont_write_overlap
  2000. X    = dont_write_simple = finalwrite = 0;
  2001. X  incompat = shiftmap = 0;
  2002. X
  2003. X  argv0 = argv[0];
  2004. X  
  2005. X  while ((c = getopt (argc, argv, ARGSTRING)) != EOF)
  2006. X    {
  2007. X      edscript = 1;
  2008. X      switch (c)
  2009. X    {
  2010. X    case 'x':
  2011. X      dont_write_simple = 1;
  2012. X      incompat++;
  2013. X      break;
  2014. X    case '3':
  2015. X      dont_write_overlap = 1;
  2016. X      incompat++;
  2017. X      break;
  2018. X    case 'i':
  2019. X      finalwrite = 1;
  2020. X      incompat++;
  2021. X      break;
  2022. X    case 'X':
  2023. X      dont_write_simple = 1;
  2024. X      /* Falls through */
  2025. X    case 'E':
  2026. X      flagging = 1;
  2027. X      /* Falls through */
  2028. X    case 'e':
  2029. X      incompat++;
  2030. X      break;
  2031. X    case '?':
  2032. X    default:
  2033. X      usage ();
  2034. X      /* NOTREACHED */
  2035. X    }
  2036. X    }
  2037. X
  2038. X  if (incompat > 1)        /* Make sure you only have one of a */
  2039. X                /* set of arguments */
  2040. X    usage ();
  2041. X  
  2042. X  if (argc - optind != 3)
  2043. X    usage ();
  2044. X
  2045. X  if (*argv[optind] == '-' && *(argv[optind] + 1) == '\0')
  2046. X    {
  2047. X      /* Sigh.  We've got standard input as the first arg. We can't */
  2048. X      /* call diff twice on stdin */
  2049. X      mapping [0] = 1;
  2050. X      mapping [1] = 2;
  2051. X      mapping [2] = 0;
  2052. X      shiftmap = 1;
  2053. X    }
  2054. X  else
  2055. X    {
  2056. X      /* Normal, what you'd expect */
  2057. X      mapping [0] = 0;
  2058. X      mapping [1] = 1;
  2059. X      mapping [2] = 2;
  2060. X      shiftmap = 0;
  2061. X    }
  2062. X
  2063. X  if (shiftmap)
  2064. X    {
  2065. X      thread1 = process_diff (argv[optind + 2], argv[optind]);
  2066. X      thread2 = process_diff (argv[optind + 2], argv[optind + 1]);
  2067. X    }
  2068. X  else
  2069. X    {
  2070. X      thread1 = process_diff (argv[optind], argv[optind + 1]);
  2071. X      thread2 = process_diff (argv[optind], argv[optind + 2]);
  2072. X    }
  2073. X  diff = make_3way_diff (thread1, thread2);
  2074. X  if (edscript)
  2075. X    output_diff3_edscript (stdout, diff, mapping, argv[optind],
  2076. X               argv[optind + 1], argv[optind + 2]);
  2077. X  else
  2078. X    output_diff3 (stdout, diff, mapping);
  2079. X  exit (overlaps);
  2080. X}
  2081. X      
  2082. X/*
  2083. X * Explain, patiently and kindly, how to use this program.  Then exit.
  2084. X */
  2085. Xvoid
  2086. Xusage ()
  2087. X{
  2088. X  fprintf (stderr, "Usage:\t%s [ -exEX3 ] [ -i ] file1 file2 file3\n",
  2089. X       argv0);
  2090. X  fprintf (stderr, "\tOnly one of [exEX3] allowed\n");
  2091. X  exit (1);
  2092. X}
  2093. X
  2094. X/*
  2095. X * Routines that combine the two diffs together into one.  The
  2096. X * algorithm used follows:
  2097. X *
  2098. X *   File0 is shared in common between the two diffs.
  2099. X *   Diff01 is the diff between 0 and 1.
  2100. X *   Diff02 is the diff between 0 and 2.
  2101. X *
  2102. X *     1) Find the range for the first block in File0.
  2103. X *          a) Take the lowest of the two ranges (in File0) in the two
  2104. X *             current blocks (one from each diff) as being the low
  2105. X *             water mark.  Assign the upper end of this block as
  2106. X *             being the high water mark and move the current block up
  2107. X *             one.  Mark the block just moved over as to be used.
  2108. X *        b) Check the next block in the diff that the high water
  2109. X *             mark is *not* from.  
  2110. X *           
  2111. X *           *If* the high water mark is above
  2112. X *             the low end of the range in that block, 
  2113. X * 
  2114. X *               mark that block as to be used and move the current
  2115. X *                 block up.  Set the high water mark to the max of
  2116. X *                 the high end of this block and the current.  Repeat b.
  2117. X * 
  2118. X *       2) Find the corresponding ranges in Files1 (from the blocks
  2119. X *          in diff01; line per line outside of diffs) and in File2.
  2120. X *          Create a diff3_block, reserving space as indicated by the ranges.
  2121. X *        
  2122. X *     3) Copy all of the pointers for file0 in.  At least for now,
  2123. X *          do bcmp's between corresponding strings in the two diffs.
  2124. X *        
  2125. X *     4) Copy all of the pointers for file1 and 2 in.  Get what you
  2126. X *          need from file0 (when there isn't a diff block, it's
  2127. X *          identical to file0 within the range between diff blocks).
  2128. X *        
  2129. X *     5) If the diff blocks you used came from only one of the two
  2130. X *         strings of diffs, then that file (i.e. the one other than
  2131. X *         file 0 in that diff) is the odd person out.  If you used
  2132. X *         diff blocks from both sets, check to see if files 1 and 2 match:
  2133. X *        
  2134. X *            Same number of lines?  If so, do a set of bcmp's (if a
  2135. X *          bcmp matches; copy the pointer over; it'll be easier later
  2136. X *          if you have to do any compares).  If they match, 1 & 2 are
  2137. X *          the same.  If not, all three different.
  2138. X * 
  2139. X *   Then you do it again, until you run out of blocks. 
  2140. X * 
  2141. X */
  2142. X
  2143. X/* 
  2144. X * This routine makes a three way diff (chain of diff3_block's) from two
  2145. X * two way diffs (chains of diff_block's).  It is assumed that each of
  2146. X * the two diffs passed are off of the same file (i.e. that each of the
  2147. X * diffs were made "from" the same file).  The three way diff pointer
  2148. X * returned will have numbering 0--the common file, 1--the other file
  2149. X * in diff1, and 2--the other file in diff2.
  2150. X */
  2151. Xstruct diff3_block *
  2152. Xmake_3way_diff (thread1, thread2)
  2153. X     struct diff_block *thread1, *thread2;
  2154. X{
  2155. X/*
  2156. X * This routine works on the two diffs passed to it as threads.
  2157. X * Thread number 0 is diff1, thread number 1 is diff2.  The USING
  2158. X * array is set to the base of the list of blocks to be used to
  2159. X * construct each block of the three way diff; if no blocks from a
  2160. X * particular thread are to be used, that element of the using array
  2161. X * is set to 0.  The elements LAST_USING array are set to the last
  2162. X * elements on each of the using lists.
  2163. X *
  2164. X * The HIGH_WATER_MARK is set to the highest line number in File 0
  2165. X * described in any of the diffs in either of the USING lists.  The
  2166. X * HIGH_WATER_THREAD names the thread.  Similarly the BASE_WATER_MARK
  2167. X * and BASE_WATER_THREAD describe the lowest line number in File 0
  2168. X * described in any of the diffs in either of the USING lists.  The
  2169. X * HIGH_WATER_DIFF is the diff from which the HIGH_WATER_MARK was
  2170. X * taken. 
  2171. X *
  2172. X * The HIGH_WATER_DIFF should always be equal to LAST_USING
  2173. X * [HIGH_WATER_THREAD].  The OTHER_DIFF is the next diff to check for
  2174. X * higher water, and should always be equal to
  2175. X * CURRENT[HIGH_WATER_THREAD ^ 0x1].  The OTHER_THREAD is the thread
  2176. X * in which the OTHER_DIFF is, and hence should always be equal to
  2177. X * HIGH_WATER_THREAD ^ 0x1.
  2178. X *
  2179. X * The variable LAST_DIFF is kept set to the last diff block produced
  2180. X * by this routine, for line correspondence purposes between that diff
  2181. X * and the one currently being worked on.  It is initialized to
  2182. X * ZERO_DIFF before any blocks have been created.
  2183. X */
  2184. X
  2185. X  struct diff_block
  2186. X    *using[2],
  2187. X    *last_using[2],
  2188. X    *current[2];
  2189. X
  2190. X  int
  2191. X    high_water_mark,
  2192. X    base_water_mark;
  2193. X
  2194. X  int
  2195. X    high_water_thread,
  2196. X    base_water_thread,
  2197. X    other_thread;
  2198. X
  2199. X  struct diff_block
  2200. X    *high_water_diff,
  2201. X    *other_diff;
  2202. X
  2203. X  struct diff3_block
  2204. X    *result,
  2205. X    *tmpblock,
  2206. X    *result_last,
  2207. X    *last_diff;
  2208. X
  2209. X  static struct diff3_block zero_diff = {
  2210. X      ERROR,
  2211. X      { {0, 0}, {0, 0}, {0, 0} },
  2212. X      { (char **) 0, (char **) 0, (char **) 0 },
  2213. X      { (int *) 0, (int *) 0, (int *) 0 },
  2214. X      (struct diff3_block *) 0
  2215. X      };
  2216. X
  2217. X  /* Initialization */
  2218. X  result = result_last = (struct diff3_block *) 0;
  2219. X  current[0] = thread1; current[1] = thread2;
  2220. X  last_diff = &zero_diff;
  2221. X
  2222. X  /* Sniff up the threads until we reach the end */
  2223. X
  2224. X  while (current[0] || current[1])
  2225. X    {
  2226. X      using[0] = using[1] = last_using[0] = last_using[1] =
  2227. X    (struct diff_block *) 0;
  2228. X
  2229. X      /* Setup low and high water threads, diffs, and marks */
  2230. X      if (!current[0])
  2231. X    base_water_thread = 1;
  2232. X      else if (!current[1])
  2233. X    base_water_thread = 0;
  2234. X      else
  2235. X    base_water_thread =
  2236. X      (D_LOWLINE (current[0], FILE0)
  2237. X       > D_LOWLINE (current[1], FILE0));
  2238. X      high_water_thread = base_water_thread;
  2239. X      
  2240. X      high_water_diff = current[high_water_thread];
  2241. X    
  2242. X      /* low and high waters start off same diff */
  2243. X      base_water_mark = D_LOWLINE (high_water_diff, FILE0);
  2244. X
  2245. X      high_water_mark = D_HIGHLINE (high_water_diff, FILE0);
  2246. X
  2247. X      /* Make the diff you just got info from into the using class */
  2248. X      using[high_water_thread]
  2249. X    = last_using[high_water_thread]
  2250. X    = high_water_diff;
  2251. X      current[high_water_thread] = high_water_diff->next;
  2252. X      last_using[high_water_thread]->next
  2253. X    = (struct diff_block *) 0;
  2254. X
  2255. X      /* And mark the other diff */
  2256. X      other_thread = high_water_thread ^ 0x1;
  2257. X      other_diff = current[other_thread];
  2258. X
  2259. X      /* Shuffle up the ladder, checking the other diff to see if it
  2260. X         needs to be incorporated */
  2261. X      while (other_diff
  2262. X         && D_LOWLINE (other_diff, FILE0) <= high_water_mark + 1)
  2263. X    {
  2264. X
  2265. X      /* Incorporate this diff into the using list.  Note that
  2266. X         this doesn't take it off the current list */
  2267. X      if (using[other_thread])
  2268. X        last_using[other_thread]->next = other_diff;
  2269. X      else
  2270. X        using[other_thread] = other_diff;
  2271. X      last_using[other_thread] = other_diff;
  2272. X
  2273. X      /* Take it off the current list.  Note that this following
  2274. X         code assumes that other_diff enters it equal to
  2275. X         current[high_water_thread ^ 0x1] */
  2276. X      current[other_thread]
  2277. X        = current[other_thread]->next;
  2278. X      other_diff->next
  2279. X        = (struct diff_block *) 0;
  2280. X
  2281. X      /* Set the high_water stuff
  2282. X         If this comparison is equal, then this is the last pass
  2283. X         through this loop; since diff blocks within a given
  2284. X         thread cannot overlap, the high_water_mark will be
  2285. X         *below* the range_start of either of the next diffs. */
  2286. X
  2287. X      if (high_water_mark < D_HIGHLINE (other_diff, FILE0))
  2288. X        {
  2289. X          high_water_thread ^= 1;
  2290. X          high_water_diff = other_diff;
  2291. X          high_water_mark = D_HIGHLINE (other_diff, FILE0);
  2292. X        }
  2293. X
  2294. X      /* Set the other diff */
  2295. X      other_thread = high_water_thread ^ 0x1;
  2296. X      other_diff = current[other_thread];
  2297. X    }
  2298. X
  2299. X      /* The using lists contain a list of all of the blocks to be
  2300. X         included in this diff3_block.  Create it.  */
  2301. X
  2302. X      tmpblock = using_to_diff3_block (using, last_using,
  2303. X                       base_water_thread, high_water_thread,
  2304. X                       last_diff);
  2305. X
  2306. X      if (!tmpblock)
  2307. X    fatal ("internal: screwup in format of diff blocks");
  2308. X
  2309. X      /* Put it on the list */
  2310. X      if (result)
  2311. X    result_last->next = tmpblock;
  2312. X      else
  2313. X    result = tmpblock;
  2314. X      result_last = tmpblock;
  2315. X
  2316. X      /* Setup corresponding lines correctly */
  2317. X      last_diff = tmpblock;
  2318. X    }
  2319. X  return result;
  2320. X}
  2321. X
  2322. X/*
  2323. X * using_to_diff3_block:
  2324. X *   This routine takes two lists of blocks (from two separate diff
  2325. X * threads) and puts them together into one diff3 block.
  2326. X * It then returns a pointer to this diff3 block or 0 for failure.
  2327. X *
  2328. X * All arguments besides using are for the convenience of the routine;
  2329. X * they could be derived from the using array.
  2330. X * LAST_USING is a pair of pointers to the last blocks in the using
  2331. X * structure.
  2332. X * LOW_THREAD and HIGH_THREAD tell which threads contain the lowest
  2333. X * and highest line numbers for File0.
  2334. X * last_diff contains the last diff produced in the calling routine.
  2335. X * This is used for lines mappings which would still be identical to
  2336. X * the state that diff ended in.
  2337. X *
  2338. X * A distinction should be made in this routine between the two diffs
  2339. X * that are part of a normal two diff block, and the three diffs that
  2340. X * are part of a diff3_block.
  2341. X */
  2342. Xstruct diff3_block *
  2343. Xusing_to_diff3_block (using, last_using, low_thread, high_thread, last_diff)
  2344. X     struct diff_block
  2345. X       *using[2],
  2346. X       *last_using[2];
  2347. X     int low_thread, high_thread;
  2348. X     struct diff3_block *last_diff;
  2349. X{
  2350. X  int lowc, highc, low1, high1, low2, high2;
  2351. X  struct diff3_block *result;
  2352. X  struct diff_block *ptr;
  2353. X  int i;
  2354. X  int current0line;
  2355. X  
  2356. X  /* Find the range in file0 */
  2357. X  lowc = using[low_thread]->ranges[0][START];
  2358. X  highc = last_using[high_thread]->ranges[0][END];
  2359. X
  2360. X  /* Find the ranges in the other files.
  2361. X     If using[x] is null, that means that the file to which that diff
  2362. X     refers is equivalent to file 0 over this range */
  2363. X  
  2364. X  if (using[0])
  2365. X    {
  2366. X      low1 = D_LOW_MAPLINE (using[0], FILE0, FILE1, lowc);
  2367. X      high1 = D_HIGH_MAPLINE (last_using[0], FILE0, FILE1, highc); 
  2368. X    }
  2369. X  else
  2370. X    {
  2371. X      low1 = D_HIGH_MAPLINE (last_diff, FILEC, FILE1, lowc);
  2372. X      high1 = D_HIGH_MAPLINE (last_diff, FILEC, FILE1, highc);
  2373. X    }
  2374. X
  2375. X  /*
  2376. X   * Note that in the following, we use file 1 relative to the diff,
  2377. X   * and file 2 relative to the corresponding lines struct.
  2378. X   */
  2379. X  if (using[1])
  2380. X    {
  2381. X      low2 = D_LOW_MAPLINE (using[1], FILE0, FILE1, lowc);
  2382. X      high2 = D_HIGH_MAPLINE (last_using[1], FILE0, FILE1, highc); 
  2383. X    }
  2384. X  else
  2385. X    {
  2386. X      low2 = D_HIGH_MAPLINE (last_diff, FILEC, FILE2, lowc);
  2387. X      high2 = D_HIGH_MAPLINE (last_diff, FILEC, FILE2, highc);
  2388. X    }
  2389. X
  2390. X  /* Create a block with the appropriate sizes */
  2391. X  result = create_diff3_block (lowc, highc, low1, high1, low2, high2);
  2392. X
  2393. X  /* Copy over all of the information for File 0.  Return with a zero
  2394. X     if any of the compares failed. */
  2395. X  for (ptr = using[0]; ptr; ptr = D_NEXT (ptr))
  2396. X    {
  2397. X      int result_offset = D_LOWLINE (ptr, FILE0) - lowc;
  2398. X      int copy_size
  2399. X    = D_HIGHLINE (ptr, FILE0) - D_LOWLINE (ptr, FILE0) + 1;
  2400. X      
  2401. X      if (!copy_stringlist (D_LINEARRAY (ptr, FILE0),
  2402. X                D_LENARRAY (ptr, FILE0),
  2403. X                D_LINEARRAY (result, FILEC) + result_offset,
  2404. X                D_LENARRAY (result, FILEC) + result_offset,
  2405. X                copy_size))
  2406. X    return 0;
  2407. X    }
  2408. X
  2409. X  for (ptr = using[1]; ptr; ptr = D_NEXT (ptr))
  2410. X    {
  2411. X      int result_offset = D_LOWLINE (ptr, FILEC) - lowc;
  2412. X      int copy_size
  2413. X    = D_HIGHLINE (ptr, FILEC) - D_LOWLINE (ptr, FILEC) + 1;
  2414. X      
  2415. X      if (!copy_stringlist (D_LINEARRAY (ptr, FILE0),
  2416. X                D_LENARRAY (ptr, FILE0),
  2417. X                D_LINEARRAY (result, FILEC) + result_offset,
  2418. X                D_LENARRAY (result, FILEC) + result_offset,
  2419. X                copy_size))
  2420. X    return 0;
  2421. X    }
  2422. X
  2423. X  /* Copy stuff for file 1.  First deal with anything that might be
  2424. X     before the first diff. */
  2425. X
  2426. X  for (i = 0;
  2427. X       i + low1 < (using[0] ? D_LOWLINE (using[0], FILE1) : high1 + 1);
  2428. X       i++)
  2429. X    {
  2430. X      D_RELNUM (result, FILE1, i) = D_RELNUM (result, FILEC, i);
  2431. X      D_RELLEN (result, FILE1, i) = D_RELLEN (result, FILEC, i);
  2432. X    }
  2433. X  
  2434. X  for (ptr = using[0]; ptr; ptr = D_NEXT (ptr))
  2435. X    {
  2436. X      int result_offset = D_LOWLINE (ptr, FILE1) - low1;
  2437. X      int copy_size
  2438. X    = D_HIGHLINE (ptr, FILE1) - D_LOWLINE (ptr, FILE1) + 1;
  2439. X
  2440. X      if (!copy_stringlist (D_LINEARRAY (ptr, FILE1),
  2441. X                D_LENARRAY (ptr, FILE1),
  2442. X                D_LINEARRAY (result, FILE1) + result_offset,
  2443. X                D_LENARRAY (result, FILE1) + result_offset,
  2444. X                copy_size))
  2445. X    return 0;
  2446. X
  2447. X      /* Catch the lines between here and the next diff */
  2448. X      current0line = D_HIGHLINE (ptr, FILE0) + 1 - lowc;
  2449. X      for (i = D_HIGHLINE (ptr, FILE1) + 1 - low1;
  2450. X       i < (D_NEXT (ptr) ?
  2451. X        D_LOWLINE (D_NEXT (ptr), FILE1) :
  2452. X        high1 + 1) - low1;
  2453. X       i++)
  2454. X    {
  2455. X      D_RELNUM (result, FILE1, i)
  2456. X        = D_RELNUM (result, FILEC, current0line);
  2457. X      D_RELLEN (result, FILE1, i)
  2458. X        = D_RELLEN (result, FILEC, current0line++);
  2459. X    }
  2460. X    }
  2461. X
  2462. X  /* Copy stuff for file 2.  First deal with anything that might be
  2463. X     before the first diff. */
  2464. X
  2465. X  for (i = 0;
  2466. X       i + low2 < (using[1] ? D_LOWLINE (using[1], FILE1) : high2 + 1);
  2467. X       i++)
  2468. X    {
  2469. X      D_RELNUM (result, FILE2, i) = D_RELNUM (result, FILEC, i);
  2470. X      D_RELLEN (result, FILE2, i) = D_RELLEN (result, FILEC, i);
  2471. X    }
  2472. X  
  2473. X  for (ptr = using[1]; ptr; ptr = D_NEXT (ptr))
  2474. X    {
  2475. X      int result_offset = D_LOWLINE (ptr, FILE1) - low2;
  2476. X      int copy_size
  2477. X    = D_HIGHLINE (ptr, FILE1) - D_LOWLINE (ptr, FILE1) + 1;
  2478. X
  2479. X      if (!copy_stringlist (D_LINEARRAY (ptr, FILE1),
  2480. X                D_LENARRAY (ptr, FILE1),
  2481. X                D_LINEARRAY (result, FILE2) + result_offset,
  2482. X                D_LENARRAY (result, FILE2) + result_offset,
  2483. X                copy_size))
  2484. X    return 0;
  2485. X
  2486. X      /* Catch the lines between here and the next diff */
  2487. X      current0line = D_HIGHLINE (ptr, FILE0) + 1 - lowc;
  2488. X      for (i = D_HIGHLINE (ptr, FILE1) + 1 - low2;
  2489. X       i < (D_NEXT (ptr) ?
  2490. X        D_LOWLINE (D_NEXT (ptr), FILE1) :
  2491. X        high2 + 1) - low2;
  2492. X       i++)
  2493. X    {
  2494. X      D_RELNUM (result, FILE2, i)
  2495. X        = D_RELNUM (result, FILEC, current0line);
  2496. X      D_RELLEN (result, FILE2, i)
  2497. X        = D_RELLEN (result, FILEC, current0line++);
  2498. X    }
  2499. X    }
  2500. X
  2501. X  /* Set correspond */
  2502. X  if (!using[0])
  2503. X    D3_TYPE (result) = DIFF_3RD;
  2504. X  else if (!using[1])
  2505. X    D3_TYPE (result) = DIFF_2ND;
  2506. X  else
  2507. X    {
  2508. X      int nl1
  2509. X    = D_HIGHLINE (result, FILE1) - D_LOWLINE (result, FILE1) + 1;
  2510. X      int nl2
  2511. X    = D_HIGHLINE (result, FILE2) - D_LOWLINE (result, FILE2) + 1;
  2512. X
  2513. X      if (nl1 != nl2
  2514. X      || !compare_line_list (D_LINEARRAY (result, FILE1),
  2515. X                 D_LENARRAY (result, FILE1),
  2516. X                 D_LINEARRAY (result, FILE2),
  2517. X                 D_LENARRAY (result, FILE2),
  2518. X                 nl1))
  2519. X    D3_TYPE (result) = DIFF_ALL;
  2520. X      else
  2521. X    D3_TYPE (result) = DIFF_1ST;
  2522. X    }
  2523. X  
  2524. X  return result;
  2525. X}
  2526. X
  2527. X/*
  2528. X * This routine copies pointers from a list of strings to a different list
  2529. X * of strings.  If a spot in the second list is already filled, it
  2530. X * makes sure that it is filled with the same string; if not it
  2531. X * returns 0, the copy incomplete.
  2532. X * Upon successful completion of the copy, it returns 1.
  2533. X */
  2534. Xint
  2535. Xcopy_stringlist (fromptrs, fromlengths, toptrs, tolengths, copynum)
  2536. X     char *fromptrs[], *toptrs[];
  2537. X     int *fromlengths, *tolengths;
  2538. X     int copynum;
  2539. X{
  2540. X  register char
  2541. X    **f = fromptrs,
  2542. X    **t = toptrs;
  2543. X  register int
  2544. X    *fl = fromlengths,
  2545. X    *tl = tolengths;
  2546. X  
  2547. X  while (copynum--)
  2548. X    {
  2549. X      if (*t)
  2550. X    { 
  2551. X      if (*fl != *tl || bcmp (*f, *t, *fl))
  2552. X         return 0;
  2553. X     }
  2554. X      else
  2555. X    { *t = *f ; *tl = *fl; }
  2556. X
  2557. X      t++; f++; tl++; fl++;
  2558. X    }
  2559. X  return 1;
  2560. X}
  2561. X
  2562. X/*
  2563. X * Create a diff3_block, with ranges as specified in the arguments.
  2564. X * Allocate the arrays for the various pointers (and zero them) based
  2565. X * on the arguments passed.  Return the block as a result.
  2566. X */
  2567. Xstruct diff3_block *
  2568. Xcreate_diff3_block (low0, high0, low1, high1, low2, high2)
  2569. X     register int low0, high0, low1, high1, low2, high2;
  2570. X{
  2571. X  struct diff3_block *result = ALLOCATE (1, struct diff3_block);
  2572. X  int numlines;
  2573. X
  2574. X  D3_TYPE (result) = ERROR;
  2575. X
  2576. X  /* Assign ranges */
  2577. X  D_LOWLINE (result, FILE0) = low0;
  2578. X  D_HIGHLINE (result, FILE0) = high0;
  2579. X  D_LOWLINE (result, FILE1) = low1;
  2580. X  D_HIGHLINE (result, FILE1) = high1;
  2581. X  D_LOWLINE (result, FILE2) = low2;
  2582. X  D_HIGHLINE (result, FILE2) = high2;
  2583. X
  2584. X  /* Allocate and zero space */
  2585. X  numlines = D_NUMLINES (result, FILE0);
  2586. X  if (numlines)
  2587. X    {
  2588. X      D_LINEARRAY (result, FILE0) = ALLOCATE (numlines, char *);
  2589. X      D_LENARRAY (result, FILE0) = ALLOCATE (numlines, int);
  2590. X      bzero (D_LINEARRAY (result, FILE0), (numlines * sizeof (char *)));
  2591. X      bzero (D_LENARRAY (result, FILE0), (numlines * sizeof (int)));
  2592. X    }
  2593. X  else
  2594. X    {
  2595. X      D_LINEARRAY (result, FILE0) = (char **) 0;
  2596. X      D_LENARRAY (result, FILE0) = (int *) 0;
  2597. X    }
  2598. X
  2599. X  numlines = D_NUMLINES (result, FILE1);
  2600. X  if (numlines)
  2601. X    {
  2602. X      D_LINEARRAY (result, FILE1) = ALLOCATE (numlines, char *);
  2603. X      D_LENARRAY (result, FILE1) = ALLOCATE (numlines, int);
  2604. X      bzero (D_LINEARRAY (result, FILE1), (numlines * sizeof (char *)));
  2605. X      bzero (D_LENARRAY (result, FILE1), (numlines * sizeof (int)));
  2606. X    }
  2607. X  else
  2608. X    {
  2609. X      D_LINEARRAY (result, FILE1) = (char **) 0;
  2610. X      D_LENARRAY (result, FILE1) = (int *) 0;
  2611. X    }
  2612. X
  2613. X  numlines = D_NUMLINES (result, FILE2);
  2614. X  if (numlines)
  2615. X    {
  2616. X      D_LINEARRAY (result, FILE2) = ALLOCATE (numlines, char *);
  2617. X      D_LENARRAY (result, FILE2) = ALLOCATE (numlines, int);
  2618. X      bzero (D_LINEARRAY (result, FILE2), (numlines * sizeof (char *)));
  2619. X      bzero (D_LENARRAY (result, FILE2), (numlines * sizeof (int)));
  2620. X    }
  2621. X  else
  2622. X    {
  2623. X      D_LINEARRAY (result, FILE2) = (char **) 0;
  2624. X      D_LENARRAY (result, FILE2) = (int *) 0;
  2625. X    }
  2626. X
  2627. X  /* Return */
  2628. X  return result;
  2629. X}
  2630. X
  2631. X/*
  2632. X * Compare two lists of lines of text.
  2633. X * Return 1 if they are equivalent, 0 if not.
  2634. X */
  2635. Xint
  2636. Xcompare_line_list (list1, lengths1, list2, lengths2, nl)
  2637. X     char *list1[], *list2[];
  2638. X     int *lengths1, *lengths2;
  2639. X     int nl;
  2640. X{
  2641. X  char
  2642. X    **l1 = list1,
  2643. X    **l2 = list2;
  2644. X  int
  2645. X    *lgths1 = lengths1,
  2646. X    *lgths2 = lengths2;
  2647. X  
  2648. X  while (nl--)
  2649. X    if (!*l1 || !*l2 || *lgths1 != *lgths2++
  2650. X    || bcmp (*l1++, *l2++, *lgths1++))
  2651. X      return 0;
  2652. X  return 1;
  2653. X}
  2654. X
  2655. X/* 
  2656. X * Routines to input and parse two way diffs.
  2657. X */
  2658. X
  2659. Xextern char *environ;        /* I hope this is here */
  2660. X
  2661. X#define    DIFF_CHUNK_SIZE    10000
  2662. X
  2663. Xstruct diff_block *
  2664. Xprocess_diff (filea, fileb)
  2665. X     char *filea, *fileb;
  2666. X{
  2667. X  char *diff_contents;
  2668. X  int diff_size;
  2669. X  char *scan_diff;
  2670. X  enum diff_type dt;
  2671. X  int i;
  2672. X  struct diff_block *block_list, *block_list_end, *bptr;
  2673. X
  2674. X  diff_size = read_diff (filea, fileb, &diff_contents);
  2675. X  scan_diff = diff_contents;
  2676. X  bptr = block_list_end = block_list = (struct diff_block *) 0;
  2677. X
  2678. X  while (scan_diff - diff_contents < diff_size)
  2679. X    {
  2680. X      bptr = ALLOCATE (1, struct diff_block);
  2681. X      bptr->lines[0] = bptr->lines[1] = (char **) 0;
  2682. X      bptr->lengths[0] = bptr->lengths[1] = (int *) 0;
  2683. X      
  2684. X      dt = process_diff_control (&scan_diff, bptr);
  2685. X      if (dt == ERROR) fatal ("Bad format in diff output");
  2686. X      if (*scan_diff != '\n') fatal ("Bad format in diff output");
  2687. X      scan_diff++;
  2688. X      
  2689. X      /* Force appropriate ranges to be null, if necessary */
  2690. X      switch (dt)
  2691. X    {
  2692. X    case ADD:
  2693. X      bptr->ranges[0][0]++;
  2694. X      break;
  2695. X    case DELETE:
  2696. X      bptr->ranges[1][0]++;
  2697. X      break;
  2698. X    case CHANGE:
  2699. X      break;
  2700. X    default:
  2701. X      fatal ("internal: Bad diff type in process_diff");
  2702. X      break;
  2703. X    }
  2704. X      
  2705. X      /* Allocate space for the pointers for the lines from filea, and
  2706. X     parcel them out among these pointers */
  2707. X      if (dt != ADD)
  2708. X    {
  2709. X      bptr->lines[0] = ALLOCATE ((bptr->ranges[0][END]
  2710. X                      - bptr->ranges[0][START] + 1),
  2711. X                     char *);
  2712. X      bptr->lengths[0] = ALLOCATE ((bptr->ranges[0][END]
  2713. X                    - bptr->ranges[0][START] + 1),
  2714. X                       int);
  2715. X      for (i = 0; i <= (bptr->ranges[0][END]
  2716. X                - bptr->ranges[0][START]); i++)
  2717. X        scan_diff = scan_diff_line (scan_diff,
  2718. X                    &(bptr->lines[0][i]),
  2719. X                    &(bptr->lengths[0][i]),
  2720. X                    diff_contents + diff_size,
  2721. X                    '<');
  2722. X    }
  2723. X      
  2724. X      /* Get past the separator for changes */
  2725. X      if (dt == CHANGE)
  2726. X    {
  2727. X      if (strncmp (scan_diff, "---\n", 4))
  2728. X        fatal ("Bad diff format: bad change separator");
  2729. X      scan_diff += 4;
  2730. X    }
  2731. X      
  2732. X      /* Allocate space for the pointers for the lines from fileb, and
  2733. X     parcel them out among these pointers */
  2734. X      if (dt != DELETE)
  2735. X    {
  2736. X      bptr->lines[1] = ALLOCATE ((bptr->ranges[1][END]
  2737. X                      - bptr->ranges[1][START] + 1),
  2738. X                     char *);
  2739. X      bptr->lengths[1] = ALLOCATE ((bptr->ranges[1][END]
  2740. X                    - bptr->ranges[1][START] + 1),
  2741. X                       int);
  2742. X      for (i = 0; i <= (bptr->ranges[1][END]
  2743. X                - bptr->ranges[1][START]); i++)
  2744. X        scan_diff = scan_diff_line (scan_diff,
  2745. X                    &(bptr->lines[1][i]),
  2746. X                    &(bptr->lengths[1][i]),
  2747. X                    diff_contents + diff_size,
  2748. X                    '>');
  2749. X    }
  2750. X      
  2751. X      /* Place this block on the blocklist */
  2752. X      if (block_list_end)
  2753. X    block_list_end->next = bptr;
  2754. X      else
  2755. X    block_list = bptr;
  2756. X      
  2757. X      block_list_end = bptr;
  2758. X      
  2759. X    }
  2760. X
  2761. X  if (scan_diff - diff_contents != diff_size)
  2762. X    fatal ("bad diff format; incomplete last line");
  2763. X
  2764. X  return block_list;
  2765. X}
  2766. X
  2767. X/*
  2768. X * This routine will parse a normal format diff control string.  It
  2769. X * returns the type of the diff (ERROR if the format is bad).  All of
  2770. X * the other important information is filled into to the structure
  2771. X * pointed to by db, and the string pointer (whose location is passed
  2772. X * to this routine) is updated to point beyond the end of the string
  2773. X * parsed.  Note that only the ranges in the diff_block will be set by
  2774. X * this routine.
  2775. X *
  2776. X * If some specific pair of numbers has been reduced to a single
  2777. X * number, then both corresponding numbers in the diff block are set
  2778. X * to that number.  In general these numbers are interpetted as ranges
  2779. X * inclusive, unless being used by the ADD or DELETE commands.  It is
  2780. X * assumed that these will be special cased in a superior routine.  
  2781. X */
  2782. X
  2783. Xenum diff_type
  2784. Xprocess_diff_control (string, db)
  2785. X     char **string;
  2786. X     struct diff_block *db;
  2787. X{
  2788. X  char *s = *string;
  2789. X  int holdnum;
  2790. X  enum diff_type type;
  2791. X
  2792. X/* These macros are defined here because they can use variables
  2793. X   defined in this function.  Don't try this at home kids, we're
  2794. X   trained professionals!
  2795. X
  2796. X   Also note that SKIPWHITE only recognizes tabs and spaces, and
  2797. X   that READNUM can only read positive, integral numbers */
  2798. X
  2799. X#define    SKIPWHITE(s)    { while (*s == ' ' || *s == '\t') s++; }
  2800. X#define    READNUM(s, num)    \
  2801. X    { if (!isdigit (*s)) return ERROR; holdnum = 0;    \
  2802. X      do { holdnum = (*s++ - '0' + holdnum * 10); }    \
  2803. X      while (isdigit (*s)); (num) = holdnum; }
  2804. X
  2805. X  /* Read first set of digits */
  2806. X  SKIPWHITE (s);
  2807. X  READNUM (s, db->ranges[0][START]);
  2808. X
  2809. X  /* Was that the only digit? */
  2810. X  SKIPWHITE(s);
  2811. X  if (*s == ',')
  2812. X    {
  2813. X      /* Get the next digit */
  2814. X      s++;
  2815. X      READNUM (s, db->ranges[0][END]);
  2816. X    }
  2817. X  else
  2818. X    db->ranges[0][END] = db->ranges[0][START];
  2819. X
  2820. X  /* Get the letter */
  2821. X  SKIPWHITE (s);
  2822. X  switch (*s)
  2823. X    {
  2824. X    case 'a':
  2825. X      type = ADD;
  2826. X      break;
  2827. X    case 'c':
  2828. X      type = CHANGE;
  2829. X      break;
  2830. X    case 'd':
  2831. X      type = DELETE;
  2832. X      break;
  2833. X    default:
  2834. X      return ERROR;            /* Bad format */
  2835. X    }
  2836. X  s++;                /* Past letter */
  2837. X  
  2838. X  /* Read second set of digits */
  2839. X  SKIPWHITE (s);
  2840. X  READNUM (s, db->ranges[1][START]);
  2841. X
  2842. X  /* Was that the only digit? */
  2843. X  SKIPWHITE(s);
  2844. X  if (*s == ',')
  2845. X    {
  2846. X      /* Get the next digit */
  2847. X      s++;
  2848. X      READNUM (s, db->ranges[1][END]);
  2849. X      SKIPWHITE (s);        /* To move to end */
  2850. X    }
  2851. X  else
  2852. X    db->ranges[1][END] = db->ranges[1][START];
  2853. X
  2854. X  *string = s;
  2855. X  return type;
  2856. X}
  2857. X
  2858. Xint
  2859. Xread_diff (filea, fileb, output_placement)
  2860. X     char *filea, *fileb;
  2861. X     char **output_placement;
  2862. X{
  2863. X  char *cmd;
  2864. X  void    *malloc();
  2865. X  int pipefd;
  2866. X  FILE *pipefp, *popenl();
  2867. X  char *diff_result;
  2868. X  long current_chunk_size;
  2869. X  int bytes;
  2870. X  int total;
  2871. X  cmd = (char *)malloc(strlen(diff_program) + strlen(filea) + strlen(fileb) + 2);
  2872. X  if (cmd == NULL) {
  2873. X      printf("Couldn't obtain memory for diff command\n");
  2874. X      exit(1);
  2875. X      }
  2876. X  pipefp = popenl(diff_program, filea, fileb, NULL, "r");
  2877. X  if (pipefp == NULL) {
  2878. X      printf("Couldn't open pipe to diff program\n");
  2879. X      exit(1);
  2880. X      }
  2881. X  pipefd = fileno(pipefp); 
  2882. X  current_chunk_size = DIFF_CHUNK_SIZE;
  2883. X  diff_result = (char *) xmalloc (current_chunk_size);
  2884. X  total = 0;
  2885. X  do {
  2886. X    bytes = myread (pipefd,
  2887. X            diff_result + total,
  2888. X            current_chunk_size - total);
  2889. X    total += bytes;
  2890. X    if (total == current_chunk_size)
  2891. X      diff_result = (char *) xrealloc (diff_result, (current_chunk_size *= 2));
  2892. X  } while (bytes);
  2893. X
  2894. X  *output_placement = diff_result;
  2895. X  pclose(pipefp);
  2896. X  return total;
  2897. X}
  2898. X
  2899. X
  2900. X/*
  2901. X * Scan a regular diff line (consisting of > or <, followed by a
  2902. X * space, followed by text (including nulls) up to a newline.
  2903. X *
  2904. X * This next routine began life as a macro and many parameters in it
  2905. X * are used as call-by-reference values.
  2906. X */
  2907. Xchar *
  2908. Xscan_diff_line (scan_ptr, set_start, set_length, limit, firstchar)
  2909. X     char *scan_ptr, **set_start;
  2910. X     int *set_length;
  2911. X     char *limit;
  2912. X     char firstchar;
  2913. X{
  2914. X  char *line_ptr = scan_ptr + 2;
  2915. X
  2916. X  if (!(scan_ptr[0] == (firstchar)
  2917. X    && scan_ptr[1] == ' '))
  2918. X    fatal ("Bad diff format; incorrect leading line chars");
  2919. X
  2920. X  *set_start = line_ptr;
  2921. X  while (*line_ptr != '\n') line_ptr++;
  2922. X  
  2923. X  if (line_ptr >= limit)
  2924. X    fatal ("Bad diff format; overflow in parse");
  2925. X
  2926. X  /* Don't include newline, but do return the beginning of the
  2927. X     next line */
  2928. X  *set_length = line_ptr - *set_start;
  2929. X
  2930. X  return line_ptr + 1;
  2931. X}
  2932. X
  2933. X/*
  2934. X * This routine outputs a three way diff passed as a list of
  2935. X * diff3_block's.
  2936. X * The argument MAPPING is indexed by external file number (in the
  2937. X * argument list) and contains the internal file number (from the
  2938. X * diff passed).  This is important because the user expects his
  2939. X * outputs in terms of the argument list number, and the diff passed
  2940. X * may have been done slightly differently (if the first argument in
  2941. X * the argument list was the standard input, for example).
  2942. X */
  2943. Xvoid
  2944. Xoutput_diff3 (outputfile, diff, mapping)
  2945. X     FILE *outputfile;
  2946. X     struct diff3_block *diff;
  2947. X     int mapping[3];
  2948. X{
  2949. X  int rev_mapping[3];
  2950. X  static int eliminate[3] = { 1, 0, 0};
  2951. X  int i;
  2952. X  int oddoneout;
  2953. X  char *cp;
  2954. X  struct diff3_block *ptr;
  2955. X  int line;
  2956. X  int dontprint;
  2957. X  static int skew_increment[3] = { 2, 3, 1 }; /* 0==>2==>1==>3 */
  2958. X
  2959. X  for (i = 0; i < 3; i++)
  2960. X    rev_mapping [mapping[i]] = i;
  2961. X
  2962. X  for (ptr = diff; ptr; ptr = D_NEXT (ptr))
  2963. X    {
  2964. X      char x[2];
  2965. X
  2966. X      switch (ptr->correspond)
  2967. X    {
  2968. X    case DIFF_ALL:
  2969. X      x[0] = '\0';
  2970. X      dontprint = 3;    /* Print them all */
  2971. X      oddoneout = 3;    /* Nobody's odder than anyone else */
  2972. X      break;
  2973. X    case DIFF_1ST:
  2974. X    case DIFF_2ND:
  2975. X    case DIFF_3RD:
  2976. X      oddoneout = rev_mapping[(int) ptr->correspond - (int) DIFF_1ST];
  2977. X        
  2978. X      x[0] = oddoneout + '1';
  2979. X      x[1] = '\0';
  2980. X      dontprint = eliminate [oddoneout];
  2981. X      break;
  2982. X    default:
  2983. X      fatal ("internal: Bad diff type passed to output");
  2984. X    }
  2985. X      fprintf (outputfile, "====%s\n", x);
  2986. X
  2987. X      /* Go 0, 2, 1 if the first and third outputs are equivalent. */
  2988. X      for (i = 0; i < 3;
  2989. X       i = (oddoneout == 1 ? skew_increment[i] : i + 1))
  2990. X    {
  2991. X      int realfile = mapping[i];
  2992. X      int
  2993. X        lowt = D_LOWLINE (ptr, realfile),
  2994. X        hight = D_HIGHLINE (ptr, realfile);
  2995. X      
  2996. X      fprintf (outputfile, "%d:", i + 1);
  2997. X      switch (lowt - hight)
  2998. X        {
  2999. X        case 1:
  3000. X          fprintf (outputfile, "%da\n", lowt - 1);
  3001. X          break;
  3002. X        case 0:
  3003. X          fprintf (outputfile, "%dc\n", lowt);
  3004. X          break;
  3005. X        default:
  3006. X          fprintf (outputfile, "%d,%dc\n", lowt, hight);
  3007. X          break;
  3008. X        }
  3009. X
  3010. X      if (i == dontprint) continue;
  3011. X
  3012. X      for (line = 0; line < hight - lowt + 1; line++)
  3013. X        {
  3014. X          fprintf (outputfile, "  ");
  3015. X          for (cp = D_RELNUM (ptr, realfile, line);
  3016. X           cp < (D_RELNUM (ptr, realfile, line)
  3017. X             + D_RELLEN (ptr, realfile, line));
  3018. X           cp++)
  3019. X        putc (*cp, outputfile);
  3020. X          putc ('\n', outputfile);
  3021. X        }
  3022. X    }
  3023. X    }
  3024. X}
  3025. X
  3026. X/*
  3027. X * This routine outputs a diff3 set of blocks as an ed script.  This
  3028. X * script applies the changes between file's 2 & 3 to file 1.  It
  3029. X * takes the precise format of the ed script to be output from global
  3030. X * variables set during options processing.  Note that it does
  3031. X * destructive things to the set of diff3 blocks it is passed; it
  3032. X * reverses their order (this gets around the problems involved with
  3033. X * changing line numbers in an ed script).
  3034. X *
  3035. X * Note that this routine has the same problem of mapping as the last
  3036. X * one did; the variable MAPPING maps from file number according to
  3037. X * the argument list to file number according to the diff passed.  All
  3038. X * files listed below are in terms of the argument list.
  3039. X *
  3040. X * Also, occasionally this routine needs the real names of the files
  3041. X * on which it works.  Thus file0, file1, and file2 are the filenames
  3042. X * passed on the command line.
  3043. X *
  3044. X * See options.h for documentation on the global variables which this
  3045. X * routine pays attention to.
  3046. X */
  3047. Xvoid
  3048. Xoutput_diff3_edscript (outputfile, diff, mapping, file0, file1, file2)
  3049. X     FILE *outputfile;
  3050. X     struct diff3_block *diff;
  3051. X     int mapping[3];
  3052. X     char *file0, *file1, *file2;
  3053. X{
  3054. X  int rev_mapping[3];
  3055. X  int i;
  3056. X  int leading_dot;
  3057. X  struct diff3_block *newblock, *thisblock;
  3058. X  char *cp;
  3059. X
  3060. X  leading_dot = 0;
  3061. X
  3062. X  for (i = 0; i < 3; i++)
  3063. X    rev_mapping [mapping [i]] = i;
  3064. X
  3065. X  newblock = reverse_diff3_blocklist (diff);
  3066. X
  3067. X  for (thisblock = newblock; thisblock; thisblock = thisblock->next)
  3068. X    {
  3069. X      /* Must do mapping correctly.  */
  3070. X      enum diff_type type
  3071. X    = ((thisblock->correspond == DIFF_ALL) ?
  3072. X       DIFF_ALL :
  3073. X       ((enum diff_type)
  3074. X        (((int) DIFF_1ST)
  3075. X         + rev_mapping [(int) thisblock->correspond - (int) DIFF_1ST])));
  3076. X
  3077. X      /* If we aren't supposed to do this output block, skip it */
  3078. X      if (type == DIFF_2ND || type == DIFF_1ST
  3079. X      || (type == DIFF_3RD && dont_write_simple)
  3080. X      || (type == DIFF_ALL && dont_write_overlap))
  3081. X    continue;
  3082. X
  3083. X      if (flagging && type == DIFF_ALL)
  3084. X    /* Do special flagging */
  3085. X    {
  3086. X      overlaps++; 
  3087. X      /* Put in lines from FILE2 with bracket */
  3088. X      fprintf (outputfile, "%da\n",
  3089. X           D_HIGHLINE (thisblock, mapping [FILE0]));
  3090. X      fprintf (outputfile, "=======\n");
  3091. X      for (i = 0;
  3092. X           i < D_NUMLINES (thisblock, mapping [FILE2]);
  3093. X           i++)
  3094. X        {
  3095. X          if (D_RELNUM (thisblock, mapping[FILE2], i)[0] == '.')
  3096. X        { leading_dot = 1; fprintf(outputfile, "."); }
  3097. X          for (cp = D_RELNUM (thisblock, mapping [FILE2], i);
  3098. X           cp < (D_RELNUM (thisblock, mapping [FILE2], i)
  3099. X             + D_RELLEN (thisblock, mapping [FILE2], i));
  3100. X           cp++)
  3101. X        putc (*cp, outputfile);
  3102. X          putc ('\n', outputfile);
  3103. X        }
  3104. X      fprintf (outputfile, ">>>>>>> %s\n.\n", file2);
  3105. X
  3106. X      /* Add in code to take care of leading dots, if necessary. */
  3107. X      if (leading_dot)
  3108. X        {
  3109. X          fprintf (outputfile, "%d,%ds/^\\.\\./\\./\n",
  3110. X               D_HIGHLINE (thisblock, mapping [FILE0]) + 1,
  3111. X               (D_HIGHLINE (thisblock, mapping [FILE0])
  3112. X            + D_NUMLINES (thisblock, mapping [FILE2])));
  3113. X          leading_dot = 0;
  3114. X        }
  3115. X
  3116. X      /* Put in code to do initial bracket of lines from FILE0  */
  3117. X      fprintf (outputfile, "%da\n<<<<<<< %s\n.\n",
  3118. X           D_LOWLINE (thisblock, mapping[FILE0]) - 1,
  3119. X           file0);
  3120. X    }
  3121. X      else if (D_NUMLINES (thisblock, mapping [FILE2]) == 0)
  3122. X    /* Write out a delete */
  3123. X    {
  3124. X      if (D_NUMLINES (thisblock, mapping [FILE0]) == 1)
  3125. X        fprintf (outputfile, "%dd\n",
  3126. X             D_LOWLINE (thisblock, mapping [FILE0]));
  3127. X      else
  3128. X        fprintf (outputfile, "%d,%dd\n",
  3129. X             D_LOWLINE (thisblock, mapping [FILE0]),
  3130. X             D_HIGHLINE (thisblock, mapping [FILE0]));
  3131. X    }
  3132. X      else
  3133. X    /* Write out an add or change */
  3134. X    {
  3135. X      switch (D_NUMLINES (thisblock, mapping [FILE0]))
  3136. X        {
  3137. X        case 0:
  3138. X          fprintf (outputfile, "%da\n",
  3139. X               D_HIGHLINE (thisblock, mapping [FILE0]));
  3140. X          break;
  3141. X        case 1:
  3142. X          fprintf (outputfile, "%dc\n",
  3143. X               D_HIGHLINE (thisblock, mapping [FILE0]));
  3144. X          break;
  3145. X        default:
  3146. X          fprintf (outputfile, "%d,%dc\n",
  3147. X               D_LOWLINE (thisblock, mapping [FILE0]),
  3148. X               D_HIGHLINE (thisblock, mapping [FILE0]));
  3149. X          break;
  3150. X        }
  3151. X      for (i = 0;
  3152. X           i < D_NUMLINES (thisblock, mapping [FILE2]);
  3153. X           i++)
  3154. X        {
  3155. X          if (D_RELNUM (thisblock, mapping [FILE2], i)[0] == '.')
  3156. X        { leading_dot = 1; fprintf (outputfile, "."); }
  3157. X          for (cp = D_RELNUM (thisblock, mapping [FILE2], i);
  3158. X           cp < (D_RELNUM (thisblock, mapping [FILE2], i)
  3159. X             + D_RELLEN (thisblock, mapping [FILE2], i));
  3160. X           cp++)
  3161. X        putc (*cp, outputfile);
  3162. X          putc ('\n', outputfile);
  3163. X        }
  3164. X      fprintf (outputfile, ".\n");
  3165. X      
  3166. X      /* Add in code to take care of leading dots, if necessary. */
  3167. X      if (leading_dot)
  3168. X        {
  3169. X          fprintf (outputfile, "%d,%ds/^\\.\\./\\./\n",
  3170. X               D_HIGHLINE (thisblock, mapping [FILE0]) + 1,
  3171. X               (D_HIGHLINE (thisblock, mapping [FILE0])
  3172. X            + D_NUMLINES (thisblock, mapping [FILE2])));
  3173. X          leading_dot = 0;
  3174. X        }
  3175. X    }
  3176. X    }
  3177. X  if (finalwrite) fprintf (outputfile, "w\nq\n");
  3178. X}
  3179. X
  3180. X/*
  3181. X * Reverse the order of the list of diff3 blocks.
  3182. X */
  3183. Xstruct diff3_block *
  3184. Xreverse_diff3_blocklist (diff)
  3185. X     struct diff3_block *diff;
  3186. X{
  3187. X  register struct diff3_block *tmp, *next, *prev;
  3188. X
  3189. X  for (tmp = diff, prev = (struct diff3_block *) 0;
  3190. X       tmp; tmp = next)
  3191. X    {
  3192. X      next = tmp->next;
  3193. X      tmp->next = prev;
  3194. X      prev = tmp;
  3195. X    }
  3196. X  
  3197. X  return prev;
  3198. X}
  3199. X
  3200. Xint
  3201. Xmyread (fd, ptr, size)
  3202. X     int fd, size;
  3203. X     char *ptr;
  3204. X{
  3205. X  int result = read (fd, ptr, size);
  3206. X  if (result < 0)
  3207. X    perror_with_exit ("Read failed");
  3208. X  return result;
  3209. X}
  3210. X
  3211. Xvoid *
  3212. Xxmalloc (size)
  3213. X     int size;
  3214. X{
  3215. X  void *result = (void *) calloc (1,size + 100);
  3216. X  if (!result)
  3217. X    fatal ("Malloc failed");
  3218. X  return result;
  3219. X}
  3220. X
  3221. Xvoid *
  3222. Xxrealloc (ptr, size)
  3223. X     void *ptr;
  3224. X     int size;
  3225. X{
  3226. X  void *result = (void *) realloc (ptr, size);
  3227. X  if (!result)
  3228. X    fatal ("Realloc failed\n");
  3229. X  return result;
  3230. X}
  3231. X
  3232. Xvoid fatal (string)
  3233. X     char *string;
  3234. X{
  3235. X  printf("%s: %s\n",argv0, string);
  3236. X  exit (1);
  3237. X}
  3238. Xvoid perror_with_exit (string)
  3239. X     char *string;
  3240. X{
  3241. X  perror (string);
  3242. X  exit (1);
  3243. X}
  3244. SHAR_EOF
  3245. echo "End of archive 2 (of 14)"
  3246. # if you want to concatenate archives, remove anything after this line
  3247. exit
  3248.